JVM Class文件结构

JVM Class文件结构

每一个class文件对应于如下所示的结构体:


JVM Class文件结构
 其中 u1,u2和u4是Class文件结构的私有数据类型,分别表示1个字节,2个字节和4个字节的无符号数

字段解释:

  • magic

魔数,魔数的唯一作用是确定这个文件是否为一个能被虚拟机所接受的Class文件。魔数值固定为0xCAFEBABE,不会改变。

  • minor_version和major_version

副版本号和主版本号,minor_version和major_version的值分别表示Class文件的副、主版本。它们共同构成了Class文件的格式版本号。譬如某个Class文件的主版本号为M,副版本号为m,那么这个Class文件的格式版本号就确定为M.m。Class文件格式版本号大小的顺序为:1.5 < 2.0 < 2.1。

一个Java虚拟机实例只能支持特定范围内的主版本号(Mi至Mj)和0至特定范围内(0至m)的副版本号。假设一个Class文件的格式版本号为V,仅当Mi.0 ≤ v ≤ Mj.m成立时,这个Class文件才可以被此Java虚拟机支持。不同版本的Java虚拟机实现支持的版本号也不同,高版本号的Java虚拟机实现可以支持低版本号的Class文件,反之则不成立

major版本对应关系:

versionmajorhex
Java SE 9530x35
Java SE 8520x34
Java SE 7510x33
Java SE 6.0500x32
Java SE 5.0490x31
JDK 1.4480x30
JDK 1.3470x2F
JDK 1.2460x2E
JDK 1.1450x2D
  • constant_pool-count

常量池计数器,constant_pool_count的值等于constant_pool表中的成员数加1。constant_pool表的索引值只有在大于0且小于constant_pool_count时才会被认为是有效的,对于long和double类型有例外情况

  • constant_pool[]

常量池,constant_pool是一种表结构(§4.4),它包含Class文件结构及其子结构中引用的所有字符串常量、类或接口名、字段名和其它常量。常量池中的每一项都具备相同的格式特征——第一个字节作为类型标记用于识别该项是哪种类型的常量,称为“tag byte”。常量池的索引范围是1至constant_pool_count−1

  • access_flags

访问标志,access_flags是一种掩码标志,用于表示某个类或者接口的访问权限及基础属性。access_flags的取值范围和相应含义:

ACC_PUBLIC:取值为0x0001

ACC_FINAL::取值为0x0010

ACC_SUPER:取值为0x0020,用于确定该Class文件里面的invokespecial指令使用的是哪一种执行语义。目前Java虚拟机的编译器都应当设置这个标志。ACC_SUPER标记是为了向后兼容旧编译器编译的Class文件而存在的,在JDK1.0.2版本以前的编译器产生的Class文件中,access_flag里面没有ACC_SUPER标志。同时,JDK1.0.2前的Java虚拟机遇到ACC_SUPER标记会自动忽略它

ACC_INTERFACE:取值为0x0200,表示是接口

ACC_ABSTRACT:取值为0x0400

ACC_SYNTHETIC:取值为0x1000, 表示并非Java源码生成的字节码

ACC_ANOTATION:0x2000,表示是注解

ACC_ENUM:取值为0x4000,表示是枚举

  • this_class

类索引,this_class的值必须是对constant_pool表中项目的一个有效索引值。constant_pool表在这个索引处的项必须为CONSTANT_Class_info类型常量,表示这个Class文件所定义的类或接口

  • super_class

父类索引,对于类来说,super_class的值必须为0或者是对constant_pool表中项目的一个有效索引值。如果它的值不为0,那constant_pool表在这个索引处的项必须为CONSTANT_Class_info类型常量,表示这个Class文件所定义的类的直接父类。当前类的直接父类,以及它所有间接父类的access_flag中都不能带有ACC_FINAL标记。对于接口来说,它的Class文件的super_class项的值必须是对constant_pool表中项目的一个有效索引值。constant_pool表在这个索引处的项必须为代表java.lang.Object的CONSTANT_Class_info类型常量。如果Class文件的super_class的值为0,那这个Class文件只可能是定义的是java.lang.Object类,只有它是唯一没有父类的类

  • interfaces_count

接口计数器,interfaces_count的值表示当前类或接口的直接父接口数量

  • interfaces[]

接口表,interfaces[]数组中的每个成员的值必须是一个对constant_pool表中项目的一个有效索引值,它的长度为interfaces_count。每个成员interfaces[i] 必须为CONSTANT_Class_info类型常量,其中0 ≤ i < interfaces_count。在interfaces[]数组中,成员所表示的接口顺序和对应的源代码中给定的接口顺序(从左至右)一样,即interfaces[0]对应的是源代码中最左边的接口。

  • fields_count

字段计数器,fields_count的值表示当前Class文件fields[]数组的成员个数。fields[]数组中每一项都是一个field_info结构的数据项,它用于表示该类或接口声明的类字段或者实例字段

  • fields[]

字段表,fields[]数组中的每个成员都必须是一个fields_info结构的数据项,用于表示当前类或接口中某个字段的完整描述。fields[]数组描述当前类或接口声明的所有字段,但不包括从父类或父接口继承的部分

  • methods_count

方法计数器,methods_count的值表示当前Class文件methods[]数组的成员个数。Methods[]数组中每一项都是一个method_info结构的数据项

  • methods[]

方法表,methods[]数组中的每个成员都必须是一个method_info结构的数据项,用于表示当前类或接口中某个方法的完整描述。如果某个method_info结构的access_flags项既没有设置ACC_NATIVE标志也没有设置ACC_ABSTRACT标志,那么它所对应的方法体就应当可以被Java虚拟机直接从当前类加载,而不需要引用其它类。method_info结构可以表示类和接口中定义的所有方法,包括实例方法、类方法、实例初始化方法方法和类或接口初始化方法方法。methods[]数组只描述当前类或接口中声明的方法,不包括从父类或父接口继承的方法

  • attributes_count

属性计数器,attributes_count的值表示当前Class文件attributes表的成员个数。attributes表中每一项都是一个attribute_info结构的数据项

  • attributes[]

属性表,attributes表的每个项的值必须是attribute_info结构。在本规范里,Class文件结构中的attributes表的项包括下列定义的属性:InnerClasses、EnclosingMethod、Synthetic、Signature、SourceFile,SourceDebugExtension、Deprecated、RuntimeVisibleAnnotations、RuntimeInvisibleAnnotations以及BootstrapMethods属性。对于支持Class文件格式版本号为49.0或更高的Java虚拟机实现,必须正确识别并读取attributes表中的Signature、RuntimeVisibleAnnotations和 RuntimeInvisibleAnnotations属性。对于支持Class文件格式版本号为51.0或更高的Java虚拟机实现,必须正确识别并读取attributes表中的BootstrapMethods属性。本规范要求任一Java虚拟机实现可以自动忽略Class文件的attributes表中的若干(甚至全部)它不可识别的属性项。任何本规范未定义的属性不能影响Class文件的语义,只能提供附加的描述信息

相关推荐