总结一下最近看的书中的知识点,以后多翻阅,都是很底层的概念
Java虚拟机规范定义了Java字节码的格式和行为,其中包括类文件结构。类文件结构中有一个重要的部分是常量池(Constant Pool),它包含了类文件中使用的所有常量信息。常量池中有多种类型的常量项,每种常量项都有其特定的结构。
先总结一下class文件解析到内存的结构,
goClassFile {
u4 magic; // 魔数,用于标识文件格式,固定为0xCAFEBABE。
u2 minor_version; // 类文件的次版本号,与major_version一起决定了该类文件的JVM版本要求。
u2 major_version; // 类文件的主版本号。比如52表示Java SE 8,53表示Java SE 9。
u2 constant_pool_count; // 常量池中的项数加1。实际项数是constant_pool_count - 1。
cp_info constant_pool[constant_pool_count - 1]; // 常量池数组,存储类文件中用到的各种常量,如类名、方法名、字符串、数字等。
u2 access_flags; // 类访问标志,用于标识类或接口的访问属性,如public、final、super、interface、abstract等。
u2 this_class; // 指向constant_pool中的索引,表示当前类的符号引用,通常是一个CONSTANT_Class_info项。
u2 super_class; // 指向constant_pool中的索引,表示当前类的父类的符号引用。如果当前类是Object类,没有父类,这个值为0。
u2 interfaces_count; // 实现的接口数。
u2 interfaces[interfaces_count]; // 实现接口的列表,每个接口都是一个对constant_pool中CONSTANT_Class_info项的索引。
u2 fields_count; // 字段数量,即类或接口中声明的字段数(不包括从父类继承的字段)。
field_info fields[fields_count]; // 字段信息的数组,每个field_info项表示一个字段的定义,如字段的名称、类型、修饰符、属性等。
u2 methods_count; // 方法数量,即类或接口中声明的方法数(不包括从父类继承的方法)。
method_info methods[methods_count]; // 方法信息的数组,每个method_info项表示一个方法的定义,如方法的名称、描述符、修饰符、属性(包括字节码)等。
u2 attributes_count; // 类的附加属性数量。
attribute_info attributes[attributes_count]; // 类文件级别的附加属性数组,比如"SourceFile"、"InnerClasses"、"EnclosingMethod"等。
}
constant_pool_coun
t 是一个无符号的短整型(u2),表示常量池中常量项的数量。常量池的索引是从1开始的,因此 constant_pool_count
的值比常量池中实际的常量项数量多1。如果 constant_pool_count 的值是20,那么常量池中有19个常量项。
常量项的通用结构如下
cp_info { u1 tag; u1 info[]; }
tag:标识常量项的类型,不同的常量项类型有不同的 tag 值。
info:根据 tag 值的不同,info 数组的内容也会有所不同。
符号引用:常量池主要用于存储类、接口、字段和方法的符号引用。这些符号引用在类加载过程中会被解析为直接引用。
字面量:常量池还存储了字符串字面量、整数和浮点数常量等。
运行时常量池:在类加载过程中,Java虚拟机会将常量池中的内容加载到方法区中的运行时常量池,供程序运行时使用。
在类加载的解析阶段,Java虚拟机会将常量池中的符号引用替换为直接引用。这个过程包括:
类或接口的解析:将类或接口的符号引用解析为指向方法区中该类或接口的直接引用。
字段解析:将字段的符号引用解析为指向具体存储位置的直接引用。
方法解析:将方法的符号引用解析为指向方法代码起始位置的直接引用。
以下是17种常量项的详细结构
javaCONSTANT_Class_info {
u1 tag; // 值为7
u2 name_index; // 指向常量池中 CONSTANT_Utf8_info 的索引
}
javaCONSTANT_Fieldref_info {
u1 tag; // 值为9
u2 class_index; // 指向常量池中 CONSTANT_Class_info 的索引
u2 name_and_type_index; // 指向常量池中 CONSTANT_NameAndType_info 的索引
}
javaCONSTANT_Methodref_info {
u1 tag; // 值为10
u2 class_index; // 指向常量池中 CONSTANT_Class_info 的索引
u2 name_and_type_index; // 指向常量池中 CONSTANT_NameAndType_info 的索引
}
javaCONSTANT_InterfaceMethodref_info {
u1 tag; // 值为11
u2 class_index; // 指向常量池中 CONSTANT_Class_info 的索引
u2 name_and_type_index; // 指向常量池中 CONSTANT_NameAndType_info 的索引
}
javaCONSTANT_String_info {
u1 tag; // 值为8
u2 string_index; // 指向常量池中 CONSTANT_Utf8_info 的索引
}
javaCONSTANT_Integer_info {
u1 tag; // 值为3
u4 bytes; // 整数值
}
javaCONSTANT_Float_info {
u1 tag; // 值为4
u4 bytes; // 浮点数值
}
javaCONSTANT_Long_info {
u1 tag; // 值为5
u4 high_bytes; // 高32位
u4 low_bytes; // 低32位
}
javaCONSTANT_Double_info {
u1 tag; // 值为6
u4 high_bytes; // 高32位
u4 low_bytes; // 低32位
}
javaCONSTANT_NameAndType_info {
u1 tag; // 值为12
u2 name_index; // 指向常量池中 CONSTANT_Utf8_info 的索引
u2 descriptor_index; // 指向常量池中 CONSTANT_Utf8_info 的索引
}
javaCONSTANT_Utf8_info {
u1 tag; // 值为1
u2 length; // UTF-8编码的字符串长度
u1 bytes[length]; // UTF-8编码的字符串
}
javaCONSTANT_MethodHandle_info {
u1 tag; // 值为15
u1 reference_kind; // 引用类型,值在1到9之间
u2 reference_index; // 指向常量池中相应的索引
}
javaCONSTANT_MethodType_info {
u1 tag; // 值为16
u2 descriptor_index; // 指向常量池中 CONSTANT_Utf8_info 的索引
}
javaCONSTANT_Dynamic_info {
u1 tag; // 值为17
u2 bootstrap_method_attr_index; // 指向BootstrapMethods属性的索引
u2 name_and_type_index; // 指向常量池中 CONSTANT_NameAndType_info 的索引
}
javaCONSTANT_InvokeDynamic_info {
u1 tag; // 值为18
u2 bootstrap_method_attr_index; // 指向BootstrapMethods属性的索引
u2 name_and_type_index; // 指向常量池中 CONSTANT_NameAndType_info 的索引
}
javaCONSTANT_Module_info {
u1 tag; // 值为19
u2 name_index; // 指向常量池中 CONSTANT_Utf8_info 的索引
}
javaCONSTANT_Package_info {
u1 tag; // 值为20
u2 name_index; // 指向常量池中 CONSTANT_Utf8_info 的索引
}
这些结构定义了常量池中每个常量项的格式,使得Java虚拟机能够正确解析和使用这些常量。每个常量项都有一个唯一的 tag
值,用于标识其类型,并跟随相应的数据结构。
本文作者:yowayimono
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!