Understand JVM:类文件结构
文章目录
- 1. class文件的内部结构
- 1.1. u4 magic
- 1.2. u2 minor_version; u2 major_version
- 1.3. u2 constant_pool_count; cp_info constant_pool[constant_pool_count-1]
- 1.4. u2 access_flags
- 1.5. u2 this_class :
- 1.6. u2 super_class
- 1.7. u2 interfaces_count; u2 interfaces[interfaces_count]; 接口索引集合,用来实现的接口格式以及接口类名
- 1.8. u2 fields_count; field_info fields[fields_count];
- 1.9. u2 methods_count; method_info methods[methods_count]
- 1.10. u2 attributes_count; attribute_info attributes[attributes_count]
Class文件是一组以8位字节为基础单位的二进制流,各个数据项目严格按照顺序紧凑的排列在Class文件之中,中间没有添加任何分隔符。
根据Java虚拟机的规定,Class文件格式采用一种类似于C语言结构体的伪结构来存储,这种伪结构中只有两种数据类型:五符号数和表。
- 无符号数属于基本的数据类型:u1、u2、u4、u8来分辨代表1个字节、2个字节、4个字节、8个字节的无符号数。
- 表是由多个无符号数或其他表作为数据项构成的符合数据类型。
class文件的内部结构
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18ClassFile {
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 super_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[attributes_count];
}
u4 magic
u4 magic是一个固定的值,每个Class文件的头4个字节成为魔数,它的唯一作用是判断这个文件是否为为一个能被虚拟机接受的Class文件,目前值是0xCAFEBABE。
u2 minor_version; u2 major_version
u2 minor_version; u2 major_version代表的是次版本号和主版本号。
u2 constant_pool_count; cp_info constant_pool[constant_pool_count-1]
u2 constant_pool_count; cp_info constant_pool[constant_pool_count-1]; 这里面代表常量池个数以及常量池信息
由于常量池中的数量是不固定的,所以在常量池的入口需要放置一项u2类型的数据,代表常量池容量计数器。
常量池中主要存放两大类常量:字面量和符号引用。
字面量比较接近Java语言层面的常量的概念,如文本字符串、被声明为final的常量值;
符号引用则属于编译原理方面的概念,包括了下面三个类常量:
- 类和接口的全限定名
- 字段的名称好描述符
- 方法的名称和描述符
u2 access_flags
u2 access_flags : 类索引,代表class访问标记,这个标志用来标识一些类或接口层次的访问信息,包括这个Class是类还是接口,是否定义为public类型、是否定义为abstract类型等等,例如:public protectedu2 this_class :
父索引,代表这个类的名称 例如 java.lang.Objectu2 super_class
接口索引结合 : 代表父类名称u2 interfaces_count; u2 interfaces[interfaces_count]; 接口索引集合,用来实现的接口格式以及接口类名
类索引和父索引都是一个u2类型的数据,而接口索引集合是一组u2类型的数据的集合,Class文件中由这三项数据来确定这个类的继承关系。
类索引用于确定这个类的全限定名;父索引用于确定确定这个类的父类的全限定名。由于Java不支持多继承,所以父类索引只有一个,除了java父索引用于确定确定这个类的父类的全限定名。由于Java不支持多继承,所以父类索引只有一个,除了java.long.Object之外,所有的Java类都有父类,因此除了java.long.Object外,所有Java类的父类索引都不为0。
接口索引集合用来描述这个类实现了哪些接口。u2 interfaces_count为接口计数器,表示索引表的容量。如果该类没有实现任何接口,那么该计数器为0,后面接口的索引表不会再占用任何字节。u2 fields_count; field_info fields[fields_count];
代表字段个数以及字段信息,用于描述接口或类中声明的变量。u2 methods_count; method_info methods[methods_count]
方法个数以及方法信息u2 attributes_count; attribute_info attributes[attributes_count]
属性表集合,在Class文件、字段表、方法表、中都有可以携带自己的属性表集合。Code属性
Java程序方法体里面的代码经过Javac编译器编译出来之后,最终变为字节码指令存储在Code属性之内。Code属性出现在方法表的属性集合之中,但并非所有的方法表都必须存在这个属性,比如抽象来和接口就不需要。Exceptions属性
列举出方法中可能抛出的异常,也就是方法描述时在throws关键字后面列举的异常。LineNumberTable属性
用于描述Java源代码行号与字节码行号之间的对应关系。