深入理解Java虚拟机(类文件结构+类加载机制+字(2)

紧接着魔数的 4 个字节存储的是 Class 文件的版本号:第 5 和第 6 两个字节是次版本号(Minor Version),第 7 和第 8 个字节是主版本号(Major Version)。高版本的 JDK 能够向下兼容低版本的 Class 文件,虚拟机会拒绝执行超过其版本号的 Class 文件。

2.2 常量池

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

因为常量池中常量的数量是不固定的,所以在常量池入口需要放置一个 u2 类型的数据来表示常量池的容量「constant_pool_count」,和计算机科学中计数的方法不一样,这个容量是从 1 开始而不是从 0 开始计数。之所以将第 0 项常量空出来是为了满足后面某些指向常量池的索引值的数据在特定情况下需要表达「不引用任何一个常量池项目」的含义,这种情况可以把索引值置为 0 来表示。

Class 文件结构中只有常量池的容量计数是从 1 开始的,其它集合类型,包括接口索引集合、字段表集合、方法表集合等容量计数都是从 0 开始。

常量池中主要存放两大类常量:字面量符号引用

字面量比较接近 Java 语言层面的常量概念,如字符串、声明为 final 的常量值等。

符号引用属于编译原理方面的概念,包括了以下三类常量:

类和接口的全限定名

字段的名称和描述符

方法的名称和描述符

2.3 访问标志

紧接着常量池之后的两个字节代表访问标志(access_flag),这个标志用于识别一些类或者接口层次的访问信息,包括这个 Class 是类还是接口;是否定义为 public 类型;是否定义为 abstract 类型;如果是类的话,是否被申明为 final 等。具体的标志位以及标志的含义见下表:

标志名称标志值含义
ACC_PUBLIC   0x0001   是否为 public 类型  
ACC_FINAL   0x0010   是否被声明为 final,只有类可设置  
ACC_SUPER   0x0020   是否允许使用 invokespecial 字节码指令的新语意,invokespecial 指令的语意在 JKD 1.0.2 中发生过改变,微聊区别这条指令使用哪种语意,JDK 1.0.2 编译出来的类的这个标志都必须为真  
ACC_INTERFACE   0x0200   标识这是一个接口  
ACC_ABSTRACT   0x0400   是否为 abstract 类型,对于接口或者抽象类来说,此标志值为真,其它类值为假  
ACC_SYNTHETIC   0x1000   标识这个类并非由用户代码产生  
ACC_ANNOTATION   0x2000   标识这是一个注解  
ACC_ENUM   0x4000   标识这是一个枚举  

access_flags 中一共有 16 个标志位可以使用,当前只定义了其中的 8 个,没有使用到的标志位要求一律为 0。

2.4 类索引、父类索引与接口索引集合

类索引(this_class)和父类索引(super_class)都是一个 u2 类型的数据,而接口索引集合(interfaces)是一组 u2 类型的数据集合,Class 文件中由这三项数据来确定这个类的继承关系。

类索引用于确定这个类的全限定名

父类索引用于确定这个类的父类的全限定名

接口索引集合用于描述这个类实现了哪些接口

2.5 字段表集合

字段表集合(field_info)用于描述接口或者类中声明的变量。字段(field)包括类变量和实例变量,但不包括方法内部声明的局部变量。下面我们看看字段表的结构:

类型名称数量
u2   access_flag   1  
u2   name_index   1  
u2   descriptor_index   1  
u2   attributes_count   1  
attribute_info   attributes   attributes_count  

字段修饰符放在 access_flags 中,它与类中的 access_flag 非常相似,都是一个 u2 的数据类型。

标志名称标志值含义
ACC_PUBLIC   0x0001   字段是否为 public  
ACC_PRIVATE   0x0002   字段是否为 private  
ACC_PROTECTED   0x0004   字段是否为 protected  
ACC_STATIC   0x0008   字段是否为 static  
ACC_FINAL   0x0010   字段是否为 final  
ACC_VOLATILE   0x0040   字段是否为 volatile  
ACC_TRANSIENT   0x0080   字段是否为 transient  
ACC_SYNTHETIC   0x1000   字段是否由编译器自动生成  
ACC_ENUM   0x4000   字段是否为 enum  
2.6 方法表集合

Class 文件中对方法的描述和对字段的描述是完全一致的,方法表中的结构和字段表的结构一样。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/95fecc785a4c846ec5c4610a9ca23f10.html