阅读Java Virtual Machine Specification中的第四章,理解Java的class文件格式。
class文件由8位的字节流组成。
The ClassFile Structure
ClassFile{
u4 magic;
u2 minor_version;
u2 major_version;
u2 constant_pool_count;
cp_info constant_pool[constant_pool_count-1];
u2 access_flags;
u2 this_class;
u2 interfaces_count;
u2 interfaces[interfaces_count];
u2 fields_count;
field_info fields[fields_count];
u2 methods_count;
method_info methods[methods_count];
u2 attributes_count;
attribute_info attributes[attrributes_count];
}
说明:u2表示无符号2字节量,u4表示无符号4字节量。
各字段的说明:
magic
一般二进制文件中都有magic number这一项,这个数说明该文件是一个class文件,它的值是0xcAFEBABE。
minor_version,major_version
class文件的版本号。
constant_pool_count
常量池表中项目数加1得到。从后面的cp_info constant_pool[constant_pool_count-1];也容易理解这个值的意思。
cp_info constant_pool[]
存储该class文件中使用到的常量信息。
access_flag
说明该class文件的访问权限和相关属性,通过位掩码来设定。 Flag Name 值 解释
ACC_PUBLIC 0x0001 public
ACC_FINAL 0x0010 final
ACC_SUPER 0x0020 跟调用invokespecial指令时的处理有关
ACC_INTERFACE 0x0200 这是个接口
ACC_ABSTRACT 0x0400 abastract
ACC_SYNTHETIC 0x1000 没有在源代码中出现,该类是编译器生成的
ACC_ANNOTATION 0x2000 注解类型
ACC_ENUM 0x4000 枚举类型
这些属性都很容易理解,比如我们定义一个类public final Test{},则Test.class的access_flag中,ACC_PUBLIC和ACC_FINAL是置位的,而ACC_INTERFACE一项肯定是0。很多类似的组合规则倒是容易自己总结出来,比如如果ACC_INTERFACE置位了,那肯定ACC_ABSTRACT也是置位的,因为接口肯定是抽象的;如果ACC_ANNOTATION置位了,那ACC_ANNOTATION肯定同时置位,等等,诸如此类。
画一个具体的位示意图表示:
this_class
一个下标,指向常量池表中代表当前类的Constant_Class_info。
super_class
为0,或者为一个下标,指向常量池中代表其父类的Constant_Class_info。如果这个值为0,那么当前类肯定是Object类。如果当前类是一个接口,该下标指向的是Object类的描述信息。
interface_count
该类实现的接口数,或者该接口实现的超接口数。
interfaces[]
具体的接口信息,每一项都是常量池表中的一个下标,指向表示接口的Constant_Class_info。
后面几个依次是字段(field),方法(methods)和属性的描述,不再赘述,