天天看点

JAVA虚拟机学习笔记3-类文件结构3.1 魔数与版本号3.2 常量池3.3 访问标志3.4 类索引、父类索引与接口索引集合3.5 字段表集合3.7 属性表集合

类文件结构

  • 3.1 魔数与版本号
  • 3.2 常量池
    • 常量池数量描述
    • 常量类型
    • Javap
    • 字面量
    • 符号引用
  • 3.3 访问标志
  • 3.4 类索引、父类索引与接口索引集合
  • 3.5 字段表集合
  • 3.7 属性表集合
    • 预定义属性
    • Code属性表的结构
    • Exceptions属性
    • LocalVariableTable属性
    • SourceFile属性
    • 其它

以下面的例子做讲解。

JAVA代码:

JAVA虚拟机学习笔记3-类文件结构3.1 魔数与版本号3.2 常量池3.3 访问标志3.4 类索引、父类索引与接口索引集合3.5 字段表集合3.7 属性表集合

CLASS文件:

JAVA虚拟机学习笔记3-类文件结构3.1 魔数与版本号3.2 常量池3.3 访问标志3.4 类索引、父类索引与接口索引集合3.5 字段表集合3.7 属性表集合

3.1 魔数与版本号

Class文件的前4个字节为魔数,十六进制:CAFEBABE (00000000:0-3)

接下来的4个字节为版本号:00 00 00 31 (0000000:4-7)代表JDK1.6.0_01 –targer1.5的版本。

3.2 常量池

常量池数量描述

前2个字节代表常量数量,如:00 16(00000000:8-9),代表有21个常量(从1开始,0是空出来的)。

常量类型

常量池的每一项常量都是一个表,常量类型如下表所示。

类型 标志 描述
CONSTANT_utf8_info 1 UTF-8编码的字符串
CONSTANT_Integer_info 3 整形字面量
CONSTANT_Float_info 4 浮点型字面量
CONSTANT_Long_info 5 长整型字面量
CONSTANT_Double_info 6 双精度浮点型字面量
CONSTANT_Class_info 7 类或接口的符号引用
CONSTANT_String_info 8 字符串类型字面量
CONSTANT_Fieldref_info 9 字段的符号引用
CONSTANT_Methodref_info 10 类中方法的符号引用
CONSTANT_InterfaceMethodref_info 11 接口中方法的符号引用
CONSTANT_NameAndType_info 12 字段或方法的符号引用
CONSTANT_MothodType_info 16 标志方法类型
CONSTANT_MethodHandle_info 15 表示方法句柄
CONSTANT_InvokeDynamic_info 18 表示一个动态方法调用点

每一个类型对应不同结构,但是有一个共同点就是每一个常量的第一个字节描述的就是类型。

下面描述2个类型的结构表。

CONSTANT_utf8_info

类型 名称 数量
u1 tag 1
u2 Length 1
u1 bytes length

例子:图中01(00000000:d)代表类型CONSTANT_utf8_info,那么接下来00 11(00000000:e-f)代表长度,长度为十进制17,那么接下来(00000010:0 - 00000020:0)代表这常量的值为:com/lin/TestClass。

CONSTANT_Class_info

类型 名称 数量
u1 tag 1
u2 name_index 1

例子:图中07(00000000:a)代表类型CONSTANT_Class_info,接下来00 02(00000000:b-c)代表引用的是第二个常量的值。

常量池中的14中常量项的结构总表如下:

常量 项目 类型 描述
CONSTANT_Utf8_info tag u1 值为1
CONSTANT_Utf8_info length u2 UF-8编码的字符串占用的字节数
CONSTANT_Utf8_info bytes u1 长度为length的UTF-8编码的字符串
CONSTANT_Integer_info tag u1 值为3
CONSTANT_Integer_info bytes u4 按照高位在前存储的int值
CONSTANT_Float_info tag u1 值为4
CONSTANT_Float_info bytes u4 按照高位在前存储的float值
CONSTANT_Long_info tag u1 值为5
CONSTANT_Long_info bytes u8 按照高位在前存储的long值
CONSTANT_Double_info tag u1 值为6
CONSTANT_Double_info bytes u8 按照高位在前存储的double值
CONSTANT_Class_info tag u1 值为7
CONSTANT_Class_info index u2 指向全限定名常量项的索引
CONSTANT_String_info tag u1 值为8
CONSTANT_String_info index u2 指向字符串字面量的索引
CONSTANT_Fieldref_info tag u1 值为9
CONSTANT_Fieldref_info index u2 指向声明字段的类或接口描述符CONSTANT_Class_info的索引项
CONSTANT_Fieldref_info index u2 指向字段名称及类型描述符CONSTANT_NameAndType_info的索引项
CONSTANT_Methodref_info tag u1 值为10
CONSTANT_Methodref_info index u2 指向声明方法的类描述符CONSTANT_Class_info的索引项
CONSTANT_Methodref_info index u2 指向方法名称及类型描述符CONSTANT_NameAndType_info的索引项
CONSTANT_InrerfaceMethodref_info tag u1 值为11
CONSTANT_InrerfaceMethodref_info index u2 指向声明方法的接口描述符CONSTANT_Class_info的索引项
CONSTANT_InrerfaceMethodref_info index u2 指向方法名称及类型描述符CONSTANT_NameAndType_info的索引项
CONSTANT_NameAndType_info tag u1 值为12
CONSTANT_NameAndType_info index u2 指向字段或方法名称常量项目的索引
CONSTANT_NameAndType_info index u2 指向该字段或方法描述符常量项的索引
CONSTANT_MethodHandle_info tag u1 值为15
CONSTANT_MethodHandle_info reference_kind u1 值必须在1~9之间,它决定方法句柄的类型。
CONSTANT_MethodHandle_info reference_index u2 值必须是对常量池的有效索引
CONSTANT_MethodType_info tag u1 值为16
CONSTANT_MethodType_info descriptor_index u2 值必须是对常量池的有效索引
CONSTANT_InvokeDynamic_info tag u1 值为18
CONSTANT_InvokeDynamic_info bootstrap_method_attr_index u2 值必须是当前Class文件中引导方法表的bootstrap_methods[]数组的有效索引
CONSTANT_InvokeDynamic_info name_and_type_index u2 值必须是当前常量池的有效索引。

Javap

我们可以利用javap命令反编译出class,常量池如下:

JAVA虚拟机学习笔记3-类文件结构3.1 魔数与版本号3.2 常量池3.3 访问标志3.4 类索引、父类索引与接口索引集合3.5 字段表集合3.7 属性表集合

字面量

类似于java中的常量,比如String,或者修饰final的常量值。

符号引用

包括下面三种常量:

  1. 类和接口的全限定名
  2. 字段的名称和描述符
  3. 方法的名称和描述符

3.3 访问标志

常量池结束后,紧接着的2个字节代表访问标志位(access_flags),这个标志位识别这个class是类还是接口;是否定义为public类型;是否定义abstract类型;是否声明为final等。标志位的含义如下表:

标志名称 标志值 含义
ACC_PUBLIC 0x0001 是否为public类型
ACC_FINAL 0x0010 是否被声明为final
ACC_SUPER 0x0020 是否使用invokespecial字节码指令,JDK1.0.2之后为真
ACC_INTERFACE 0x0200 标示为一个接口
ACC_ABSTRACT 0x0400 是否为abstract:接口和抽象类为真
ACC_SYNTHETIC 0x1000 表示这个类并非用户代码产生的
ACC_ANNOTATION 0x2000 表示这是一个注解
ACC_ENUM 0x4000 表示这是一个枚举

例子:00 21(000000d0:7-8)代表此类为public类。

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

类索引:u2类型的数据。00 01(000000d0:9-a),引用第1个常量。即:com.lin.TestClass

父类索引:u2类型的数据。00 03(000000d0:b-c),引用第3个常量。即:java.lang.Object

接口索引:一组u2类型的数据。00 00(000000d0:d-e),为0代表没有实现接口。如果有实现接口,那么这个数代表实现多少个接口,接下来的多少个u2指向对于接口。

3.5 字段表集合

用于描述接口或者类中声明的变量。包括类级变量以及实例级变量,但不包括方法内部变量。

Class字段表集合第一个u2字节代表变量数量,之后开始描述各个变量。

例子:00 01(000000d0:f – 000000e0:0)代表变量数量为1。

变量的描述结构如下:

类型 名称 数量
u2 access_flags 修饰位 1
u2 name_index 变量名称 1
u2 descriptor_index 变量类型 1
u2 attributes_count 属性表集合数量 1
attribute_info Attributes 属性表 attributes_count

其中修饰位对应表如下

标志位名称 标志值 含义
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

其中变量类型对应表如下

标识字符 含义 标识字符 含义
B 基本类型byte J 基本类型long
C 基本类型char S 基本类型short
D 基本类型double Z 基本类型boolean
F 基本类型float V 特殊类型void
I 基本类型int L 对象类型

例子1: 00 02(000000e0:1-2)代表修饰符,private

00 05(000000e0:3-4)代表名称,映射到常量第5个。

00 06(000000e0:5-6)代表变量类型,6代表映射到常量第6个。

00 00(000000e0:7-8)代表属性表数量,这里为0。

注:属性表将在3.7中的属性表集合介绍。

#3.6 方法表集合

存储对方法的描述。第一个u2是描述方法数量。

例子:00 02(000000e0:9-a)代表存在2个方法

结构与字段表集合类似,结构如下

类型 名称 数量
u2 access_flags 修饰位 1
u2 name_index 方法名称 1
u2 descriptor_index 方法描述符 1
u2 attributes_count 属性表集合数量 1
attribute_info Attributes 属性表 attributes_count

其中修饰位对应表如下

标志位名称 标志值 含义
ACC_PUBLIC 0x0001 Public
ACC_PRIVATE 0x0002 Private
ACC_PROTECTED 0x0004 Protected
ACC_STATIC 0x0008 Static
ACC_FINAL 0x0010 Final
ACC_SYNCHRONIZED 0x0020 synchronized
ACC_BRIDGE 0x0040 方法是否有编译器产生的桥接方法
ACC_VARARGS 0x0080 方法是否接受不定参数
ACC_NATIVE 0x0100 native
ACC_ABSTRACT 0x0400 abstract
ACC_STRICTFP 0x0800 strictifp
ACC_ENUM 0x1000 native

例子1:00 01(000000e0:b-c)代表修饰符,public

00 07(000000e0:d-e)代表方法名称,常量第7个:

00 08(000000e0:f-000000f0:0)代表方法描述符,常量第8个:()V。

00 01(000000f0:1-2)代表方法在属性表集合存在1个属性。

00 09(000000f0:3-4)代表属性对应第9个常量:Code

例子2:00 01(00000120:8-9)代表修饰符,public

00 10(00000120:a-b)代表方法名称,常量第16个:inc

00 11(00000120:c-d)代表方法描述符,常量第17个:()I。

00 01(00000120:c-d)代表方法在属性表集合存在1个熟悉。

00 09(00000130:0-1)代表属性对应第9个常量:Code

3.7 属性表集合

存在于字段表集合和方法表集合里面,用于描述某些场景专有的信息。

预定义属性

预定义的属性表如下21项:

属性名称 使用位置 含义
Code 方法表 Java代码编译成的字节码指令
ConstantValue 字段表 final关键字定义的常量池
Deprecated 类,方法,字段表 被声明为deprecated的方法和字段
Exceptions 方法表 方法抛出的异常
EnclosingMethod 类文件 仅当一个类为局部类或者匿名类是才能拥有这个属性,这个属性用于标识这个类所在的外围方法
InnerClass 类文件 内部类列表
LineNumberTable Code属性 Java源码的行号与字节码指令的对应关系
LocalVariableTable Code属性 方法的局部便狼描述
StackMapTable Code属性 JDK1.6中新增的属性,供新的类型检查检验器检查和处理目标方法的局部变量和操作数有所需要的类是否匹配
Signature 类,方法表,字段表 用于支持泛型情况下的方法签名
SourceFile 类文件 记录源文件名称
SourceDebugExtension 类文件 用于存储额外的调试信息
Synthetic 类,方法表,字段表 标志方法或字段为编译器自动生成的
LocalVariableTypeTable 使用特征签名代替描述符,是为了引入泛型语法之后能描述泛型参数化类型而添加
RuntimeVisibleAnnotations 类,方法表,字段表 为动态注解提供支持
RuntimeInvisibleAnnotations 表,方法表,字段表 用于指明哪些注解是运行时不可见的
RuntimeVisibleParameterAnnotation 方法表 作用与RuntimeVisibleAnnotations属性类似,只不过作用对象为方法
RuntimeInvisibleParameterAnnotation 方法表 作用与RuntimeInvisibleAnnotations属性类似,作用对象哪个为方法参数
AnnotationDefault 方法表 用于记录注解类元素的默认值
BootstrapMethods 类文件 用于保存invokeddynamic指令引用的引导方式限定符

Code属性表的结构

类型 名称 数量
u2 attribute_name_index 1
u4 attribute_length 1
u2 max_stack 1
u2 max_locals 1
u4 code_length 1
u1 code code_length
u2 exception_table_length 1
exception_info exception_table exception_length
u2 attributes_count 1
attribute_info attributes attributes_count

例子:00 09(000000f0:3-4)代表属性对应第9个常量:Code

00 00 00 2F(000000f0:5-8)代表属性长度为十进制47。

00 01(000000f0:9-a)代表操作数栈为1。

00 01(000000f0:b-c)代表局部变量存储空间,单位是slot。

00 00 00 05(000000f0:d-00000100:0)代表字节码指令数。

2A B7 00 0A B1(00000100:1-5)代表5个指令,请查看指令表对应。

00 00(00000100:6-7)代表异常属性表长度,0代表不存在。

00 02(00000100:8-9)代表存在2个附加属性。

Exceptions属性

与Code属性平级的属性。与异常表不一样,异常表在于属性里面。

与Code属性平级的属性。与异常表不一样,异常表在于属性里面。

类型 名称 数量
u2 attribute_name_index 1
u2 attribute_lrngth 1
u2 attribute_of_exception 1
u2 exception_index_tsble number_of_exceptions

LineNumberTable属性

用于描述java源码行号与字节码行号对应关系,结构如下:

类型 名称 数量
u2 attribute_name_index 1
u4 attribute_length 1
u2 line_number_table_length 1
line_number_info line_number_table line_number_table_length

例子:00 0C(00000100:a-b)代表属性名称,对应常量第12个,即:LineNumberTable。

00 00 00 06(00000100:c-f)代表属性长度,为6。

00 01(00000110:0-1)代表1个集合的对应表。

00 00 00 03(00000110:2-5)前面一个u2代表字节码行号,后面一个u2代表java源码行号。

LocalVariableTable属性

类型 名称 数量
U2 Attribute_name_index 1
U4 Attribute_length 1
U2 local_variable_table_length 1
Local_variable_info local_variable_table Local_variable_table_length

其中local_variable_info的结构如下

类型 名称 数量
u2 Start_pc 1
u2 Length 1
u2 Name_index 1
u2 Descriptor_index 1
u2 index 1

例子:00 0D(00000110:6-7)代表代表属性名称,对应常量第13个,即:LocalVariableTable。

00 00 00 0C(00000110:8-b)代表属性长度为十进制12。

00 01(00000110:c-d)代表localtable长度为1。

00 00 00 05 00 0E 00 0F 00 00(00000110:e-00000120:7)代表local_variable_info。第一个u2(00 00)代表局部变量生命周期开始字节码偏移量;第二个u2(00 05)代表作用范围长度;第三个u2(00 0E)代表局部变量名,对应常量表。第四个u2(00 0F)代表局部变量描述符,对应常量表。第五个u2(00 00)代表局部变量的slot位置。

SourceFile属性

用于记录生成这个Class文件的源码文件名称。在方法表集合后面。结构如下

类型 名称 数量
U2 Attribute_name_index 1
U4 Attribute_length 1
U2 Sourcefile_index 1

例子:00 14(00000160:9-a)代表属性名称,对应常量表十进制20,即:SourceFile

00 00 00 02(00000160:b-e)代表属性长度,为2。

00 15(00000160:f-00000170:0)代表属性数据,对应常量表十进制21,即:TestClass.java

其它

其它属性就不在一一列举。

另外可以使用javap –verbose命令反编译等到结果,便于查看方法内容。

JAVA虚拟机学习笔记3-类文件结构3.1 魔数与版本号3.2 常量池3.3 访问标志3.4 类索引、父类索引与接口索引集合3.5 字段表集合3.7 属性表集合