java 类文件结构

时间:2021-12-15 13:54:26
  

 1  Class文件与虚拟机:

Java 虚拟机不和包括Java 在内的任何语言绑定,它只与“Class文件”这种特定的二进制文件格式所关联,Class文件包含了Java虚拟机指令集和符号表以及若干其他辅助信息。基于安全方面的考虑,Java 虚拟机规范要求Class文件中使用许多强制性的语法和结构化约束,但任何一门语言都可以表示为一个能被Java虚拟机所接受的有效的Class文件。Java虚拟机不用关心Class的来源为何种语言

 

2 Class文件的结构

Class文件是一组以8位字节为基础的二进制流,各个数据项严格按照顺序紧凑地排列在Class文件之中,中间没有任何的分隔符,这使得整个Class文件中存储的内容几乎全部是程序运行的必要数据,没有空隙存在。

Class的结构不像XML等描述语言,由于没有分隔符,所以先后顺序以及长度都不允许发生改变。

2.1 Class文件版本

每个Class文件头四个字节称为魔数,它的唯一作用是确定这个文件是否为一个能被虚拟机接受的Class文件。很多文件存储标准中都是用魔数而不是使用扩展名来识别,譬如图片格式。用魔数而不是使用扩展名来识别主要基于安全方面的考虑,因为文件名可以随意的改动。

 紧接着魔数的四个字节存储的是Class文件的版本号:第5和第6个字节是次版本号,第7和第8个字节是主版本号。Java的版本号是从45开始的,高版本的JDK能向下兼容以前版本的Class文件,但不能运行以后版本的文件。

 java 类文件结构

2.2 常量池

   紧接着主版本号之后的是常量池入口,常量池可以理解为Class文件之中的资源仓库,它是Class文件结构中与其他项目关联最多的数据类型,也是占用Class文件空间最大的数据项目之一,同时它还是Class文件中第一个出现的表类型数据项目。

   由于常量池中的数量不固定,所以在常量池的入口需要放置一项u2类型的数据,代表常量池计数值,这个容量计数值是以1开始计数而不是0。Class文件结构中只有常量池的容量计数是从1开始的,对于其他集合类型,包括接口索引集合、字段表集合、方法表集合等的容量计数与一般习惯相同,都是从0开始的。

常量池主要存放两大类常量:字面常量和符号引用。字面常量比较接近Java语言层面的常量概念,比如文本字符串,声明的final 的常量等。而符号引用过常量则属于编译原理方面的概念,包括下面三类常量:

类和接口的权限定名

字段的名称和描述符

方法的名称和描述符

Java 代码在进行Javac编译的时候,是在虚拟机加载Class文件的时候进行动态连接。也就是说,在Class文件中不会保存各个方法、字段的最终内存布局信息,因此这些字段,方法的符号引用不经过运行期转换的话无法得到真正的内存入口地址,也就无法直接被虚拟机使用。

对于源代码如下:

public class ClassStudy {

private static final int ss=22;

public static void main(String[] args) {
System.out.println(ss);
}

}


 

利用jdk自带的反汇编工具javap输出常量表

java 类文件结构


 java 类文件结构

java 类文件结构


2.3 访问标志

在常量池结束之后,紧接着的两个字节代表访问标志,这个标志用于识别一些类或者接口层次的信息,包括:这个Class是类还是接口;是否为public类型,是否定义为abstract类型;如果是类的话,是否被声明为final等。

 

2.3 类索引、父类索引与接口索引的集合

类索引和父类索引都是一个u2类型的数据,而接口索引是一组u2类型的数据集合,Class文件有这三项数据确定这个类的继承关系。类索引用于确定这个累的全限定名,父类索引用于确定这个类的父类的权限定名。

类索引、父类索引和接口索引集合都顺序排列在访问标志之后,类索引和父类索引两个u2类型的索引值表示。

对于接口索引集合,入口的第一项u2类型计数器,表示索引表的容量。如果该类没有任何的接口,则计数器值为0,后面的索引不在占用任何字节。

 

2.4 字段表集合

  字段表用于描述接口或者类中的声明的变量。字段包括类级变量以及实例变量,但不包括在方法内部的局部变量。