2.class文件详解
我们可任意打开一个Class文件(使用Hex Editor,sublime等工具打开),内容如下(内容是16进制):
开头的4个字节 代表的是魔数 它的唯一作用是确定这个文件是否是一个能被虚拟机接收的Class文件。后面4个字节代码的是使用的jdk版本号。其中前2个字节代码次版本号,后面2个字节代码主版本号。
JDK版本号信息对照表:
常量池计数器
常量池是class文件中非常重要的结构,它描述着整个class文件的字面量信息。
常量池是由一组constant_pool结构体数组组成的,而数组的大小则由常量池计数器指定。
常量池计数器constant_pool_count 的值 =constant_pool表中的成员数+ 1。
constant_pool表的索引值只有在大于 0且小于constant_pool_count时才会被认为是有效的。
有很多可以观察ByteCode的方法:
1.javap -v 命令
2.JClassLib ----IDEA的插件之一,非常方便
注意事项:
常量池计数器默认从1开始而不是从0开始:
当constant_pool_count = 1时,常量池中的cp_info个数为0;当constant_pool_count为n时,常量池中的cp_info个数为n-1。
原因:
在指定class文件规范的时候,将索引#0项常量空出来是有特殊考虑的,这样当:某些数据在特定的情
况下想表达“不引用任何一个常量池项”的意思时,就可以将其引用的常量的索引值设置为#0来表示。
常量池数据区
访问标志
访问标志,access_flags 是一种掩码标志,用于表示某个类或者接口的访问权限及基础属性。
类索引
类索引,this_class的值必须是对constant_pool表中项目的一个有效索引值。constant_pool表在这个索引处的项必须为CONSTANT_Class_info 类型常量,表示这个 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[]数组中的每个成员的值必须是一个对constant_pool表中项目的一个有效索引值, 它的长度为 interfaces_count。
每个成员interfaces[i] 必须为CONSTANT_Class_info类型常量,其中 【0 ≤ i <interfaces_count】。
在interfaces[]数组中,成员所表示的接口顺序和对应的源代码中给定的接口顺序(从左至右)一样,即interfaces[0]对应的是源代码中最左边的接口。
字段计数器
字段计数器,fields_count的值表示当前 Class 文件 fields[]数组的成员个数。
fields[]数组中每一项都是一个field_info结构的数据项,它用于表示该类或接口声明的【类字段】或者【实例字段】。
字段信息数据区字段表,fields[]数组中的每个成员都必须是一个fields_info结构的数据项,用于表示当前类或接口中某个字段的完整描述。
fields[]数组描述当前类或接口声明的所有字段,但不包括从父类或父接口继承的部分。
方法计数器
方法计数器, methods_count的值表示当前Class 文件 methods[]数组的成员个数。Methods[]数组中每一项都是一个 method_info 结构的数据项。
方法信息数据区
方法表,methods[] 数组中的每个成员都必须是一个 method_info 结构的数据项,用于表示当前类或接口中某个方法的完整描述。
如果某个method_info 结构的access_flags 项既没有设置 ACC_NATIVE 标志也没有设置ACC_ABSTRACT 标志,那么它所对应的方法体就应当可以被 Java 虚拟机直接从当前类加载,而不需要引用其它类。
method_info结构可以表示类和接口中定义的所有方法,包括【实例方法】、【类方法】、【实例初始化方法】和【类或接口初始化方法】。
methods[]数组只描述【当前类或接口中声明的方法】,【不包括从父类或父接口继承的方法】。
属性计数器
属性计数器,attributes_count的值表示当前 Class 文件attributes表的成员个数。attributes表中每一项都是一个attribute_info 结构的数据项。
属性信息数据区
属性表,attributes 表的每个项的值必须是attribute_info结构。
在Java 7 规范里,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 7 规范 要求任一 Java 虚拟机实现可以自动忽略 Class 文件的 attributes表中的若干 (甚至全部) 它不可识别的属性项。
任何本规范未定义的属性不能影响Class文件的语义,只能提供附加的描述信息。