《深入理解Java虚拟机》读书笔记,java字节码文件的这块定义的数据结构比较多,书讲解的很详细。
一.class文件中的数据格式
字节码文件是由java源文件经过编译之后获得,是以8位字节为基础单位的二进制流,各个数据严格按照顺序紧凑地排列在class文件之中,中间没有任何分割符,当数据项占用8位字节以上的空间时,按照高位在前(大端法)的方式分割成若干个8位字节进行存储。
class文件中的格式只有俩种数据类型:无符号数和表
无符号数:为基本类型的数据类型,以u1,u2,u4,u8来代表1个字节,2个字节,4个字节,8个字节的无符号数。无符号数可以用来描述“数字、索引引用、数量值或者按照utf-8编码构成的字符串值。
表:表是由多个无符号数或者其他表作为数据项构成的复杂数据类型。所有表都习惯以“_info”结尾。表用于描述有层次关系的复杂结构的数据。如下:
表中描述的标签有“类型、名称、数量”,对于一段由0和1组成的序列来说,有了类型,那么就知道了数据的大小,去读取数据大小的字节即可,通过名称可以知道数据所要表达的意思,数量则可以知道有多少个这样的数据类型。
举个例子来说的话,有一段序列是代表一张表,其中表中每一项的类型和数量是已经的,且是顺序排序的。那么在读取的时候按照固定的字节去读取进行解析即可。
二. class文件格式
整个class文件也是一张表。下图中可以看出编译之后class文件中包含了常量池、字段表、接口表、属性表等。
在文件中的存储如下:
三.常量池
常量池中存放俩大类常量:字面量和符号引用。
字面量:文本字符串、声明为final的常量值等
符号引用:类和接口的全限定名、字段名称和描述符、方法的名称和描述符
常量池的项目类型:
常量池中的每一种类型都是一张表,且结构各不相同。在java编译期编译java源文件时,把源文件中的有关类,字段,方法相关的信息全部放入class字节码的常量池中,class文件中的字段表,方法表中可以通过常量池中的“常量”索引去访问对应的常量项,拿到类或方法,字段等信息。
java虚拟机在运行java程序时,首先去加载class文件,通过class文件,java虚拟机才知道对象有那些方法,字段,然后去内存分配空间,进行运算。
3.1 CONSTANT_Class_info
class_info表中tag所占1个字节,值为7,代表为class_info。index指向CONSTANT_Utf8_info表,其内容为类的全限定名。
3.2 CONSTANT_Fieldref_info
第一个index是声明字段的类的CONSTANT_Class_info索引项,通过这个索引可以知道字段是哪个类声明的。
第二个index是CONSTANT_NameAndType的索引项。
3.3 CONSTANT_NameAndType
CONSTANT_NameAndType中的内容包含了字段的名称和描述符,描述符用来表示字段的数据类型(基本类型或者对象)。
3.4 CONSTANT_Method_Type_info
四. 字段表
上表中name_index和descriptor_index都是对常量池的引用。name_index代表字段的名称,descriptor_index代表字段的描述符。
字段表集合中不会列出从超类或者父接口中继承而来的字段。
内部类中为了保持对外部类的访问性,会自动添加指向外部类实例的字段。
五. 方法表
其中name_index和descriptor_index和属性表中一样,代表方法的名称和方法的描述符。
六.属性表
6.1 Code属性
6.2 Exceptions属性
Exceptions属性是列举方法中可能抛出的受查异常,也就是throws关键子后面列举的异常。
6.3 LocalVariableTable属性
其中local_variable_info表示的方法中的形参和局部变量。start_pc和length表示变量的作用域。
6.4 ConstantValue属性
ConstantValue属性的作用是通知虚拟机自动为静态变量赋值。
static类型的的变量,有俩种赋值方式,一种是在类构造器<clinit>方法中,另一种是通过ConstantValue属性。Sun Javac编译器中,如果同时使用final和static来修饰一个变量,并且这个变量的数据类型是基本类型或者String类型的话,就生成Constant属性来进行初始化。
6.5 InnerClasses 属性
InnerClasses属性用于记录内部类与宿主类之间的关联。
数据类number_of_classes代表需要记录多少个内部类,每个内部类的信息都由一个inner_classes_info表进行描述。
- inner_class_info_index和outer_class_info_index都是指向常量池中
CONSTANT_Class_info型常量的索引 - inner_name_index是指向常量池中CONSTANT_Utf8_info型常量的索引,代表这个类的名称,如果是匿名内部类,那么这项值为0.
- inner_class_access_flags是内部类的访问标志
6.6 Signature 属性
Signature属性记录的是泛型签名信息。java语言的泛型采用的是擦除法,在字节码中,泛型信息都被擦除掉了。JDK1.5之后,任何类、接口、初始化方法或成员的泛型签名中如果包含了类型变量或者“参数化类型”,则Signature属性会为它记录泛型签名信息。