Class类文件的结构

时间:2023-03-09 01:16:15
Class类文件的结构

  Class文件是一组以8位字节为基础单位的二进制流,各个数据项目严格按照顺序紧凑的排列在Class文件中,中间没有任何分隔符。Class文件的结构只有两种数据类型:无符号数和表。无符号数以u1、u2、u4和u8来代表1个字节、两个字节、四个字节和八个字节的无符号数,可以用来描述数字、索引引用、数值量或者按UTF-8编码的字符串值。表是有多个无符号数或者其他表作为数据项构成的复合数据类型,习惯性以“_info”结尾。下面是Class文件的结构:

类 型 名 称 数 量
u4 magic 1
u2 minor_version 1
u2 major_version 1
u2 constant_pool_count 1
cp_info constant_pool constant_pool_count-1
u2 access_flag 1
u2 this_class 1
u2 super_class 1
u2 interfaces_count 1
u2 inferfaces interfaces_count
u2 fields_count 1
field_info fields fields_count
u2 methods_count 1
method_info methods methods_count
u2 attributes_count 1
attributes_info attributes attributes_count

1.魔数magic与Java版本号

  每个Class前四个字节称为魔数,唯一作用是确定这个文件是否为一个能被虚拟机接受的Class文件,该魔数为0xCAFEBABE。

  紧接着魔数的四个字节存储的是Class的版本号。

2.常量池constant_pool

  常量池入口放置容量计数值,该计数值是从1而不是从0开始的。

  主要存放两大类常量:字面量和符号引用。字面量接近于Java语言层面的常量概念,如文本字符串,声明为final的常量值等。符号引用是编译原理方面的概念,包括三类常量:类和接口的全限定名,字段的名称和描述符,方法的名称和描述符。常量池的每一项常量都是一个表,JDK1.7总用有14种表,表开始都是一个u1类型的标志位,代表这种常量属于哪种常量类型。这14种表又各有自己的结构。

3.访问标志access_flag

  用于识别类或接口层次的访问信息,包括:这个Class是类还是接口;是否定义为public类型;是否定义为abstract类型;是否声明为final等。

4.类索引、父类索引与接口索引集合

  这三项数据确定了这个类的继承关系。

  类索引和父类索引用两个u2类型的索引值表示,它们各自指向一个类型为Constant_Class_info的类描述符常量,通过Constant_Class_info类型的常量中的索引值可以找到定义在Constant_Utf8_info类型的常量中的全限定名字符串。下面是类索引查找过程:

  Class类文件的结构

5.字段表集合

  字段表用来描述接口或类中声明的变量。下面是字段表的格式

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

  描述符的作用是用来描述字段的数据类型、方法的参数列表和返回值。基本数据类型以及代表无返回值的void类型都用一个大写字符表示,而对象类型则用字符L加对象的全限定名来表示。对于数组类型,每一维度增加一个“[”前缀来表示,如定义一个java.lang.String[][]类型的二维数组,则被记录为“[[java/lang/String;”,后面的分号是为了隔开连续的多个全限定名。

  用描述符来描述方法时,按照先参数列表后返回值的顺序描述,参数列表按照参数的严格顺序放在一组小括号“()”中。例如

int indexOf(char[] source, int sourceOffset, int sourceCount,
char[] target, int targetOffset, int targetCount, int fromIndex) { ... }
//描述符为
//([CII[CIII)I

6.方法表集合

  方法表结构与字段表完全相同。

  如果子类没有重写父类的方法,方法表集合就不会出现父类的方法。编译器可能自动添加方法,最典型的是类构造器“<clinit>”方法和实力构造器“<init>”方法。

7.属性表集合

  在Class文件、字段表、方法表中都可以携带自己的属性表集合,用于描述某些场景专有的信息。