而运行时常量池是方法区的一部分,文字解释:
运行时常量池(Runtime Constant Pool)是方法区的一部分。Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池表(ConstantPool Table), 用于存放编译器生成的各种字面量与符号引用,这部分内容将在类加载后存放到方法区的运行时常量池中。
从这段描述中我们可以得出结论,运行时常量池里面存放的是从Class文件中的常量池表中加载到的数据,为了搞清楚运行时常量池里有什么,我们需要搞清楚对应常量池表里面有什么
2. 常量池表
2.1 Class文件的数据类型
先说一下Class的文件格式:Class文件的文件格式采用一种类似于C语言结构体的伪结构来存储数据,这种伪结构中只有两种数据类型,“无符号数”和“表”。
- 无符号数属于基本的数据类型,以u1/u2/u4/u8来分别代表1个字节、2个字节、4个字节、8个字节的的无符号数,无符号数可以用来描述数字、索引引用、数量值或者按utf-8编码构成字符串值。
- 表是由多个无符号数或者其他表作为数据项构成的符合数据类型,为了便于区分,所有表的命名都习惯性地以“_info”结尾。表用于描述有层次关系的复合结构的数据,整个Class文件本质上也可以视作是一张表。
2.2 常量池
常量池可以比喻为Class文件里的资源仓库,它是Class文件结构中与其他项目关联最多的数据。
常量池中主要存放两大数据:字面量和符号引用。字面量比较接近Java语言层面的常量概念,如文本字符串、被声明为final的常量值等。
2.2.1 符号引用
由于Java代码在进行Javac编译的时候,并不像C/C++那样有“连接”这一步骤,而是在虚拟机加载Clsss文件的时候进行动态连接,因此,在我们将Java代码编译成Class文件后,Class文件并不会保存方法、字段等在内存中的布局。为了解决这个问题,Class文件会在常量池内保存方法、字段等的符号引用。所谓符号引用,我们可以简单的理解为真正内存布局的占位符,在类加载过程的解析阶段,符号引用会被替换为真正的直接引用。
2.2.2 常量池的结构
常量池中每一项常量都是一个表,这些表都有一个共同的特点,即表结构的起始第一位为一个u1类型的标志位,代表着当前常量属于哪一种常量类型
常量池中的项目类型
项目 | 类型 | 描述 |
---|
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_MethodHandle_info | 15 | 表示方法句柄 | CONSTANT_MethodType_info | 16 | 表示方 |
《一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》
【docs.qq.com/doc/DSmxTbFJ1cmN1R2dB】 完整内容开源分享
法类型 | | CONSTANT_Dynamic_info | 17 | 表示一个动态计算常量 | | CONSTANT_InvkoeDynamic_info | 18 | 表示一个动态方法调用点 | | CONSTANT_Module_info | 19 | 表示一个模块 | | CONSTANT_Package_info | 20 | 表示一个模块中开放或者导出的包 |
具体表信息和表结构如下:
2.2.2.1 CONSTANT_Utf8_info
类型 | 标志 | 描述 |
---|
tag | u1 | 值为1 | length | u2 | UTF-8编码的字符串占用的字节数 | bytes | u1 | 长度为length的UTF-8编码的字符串,总共length个 |
2.2.2.2 CONSTANT_Integer_info
项目 | 类型 | 描述 |
---|
tag | u1 | 值为3 | bytes | u4 | 按照高位在前存储的int值 |
2.2.2.3 CONSTANT_Float_info
项目 | 类型 | 描述 |
---|
tag | u1 | 值为4 | bytes | u4 | 按照高位在前存储的float值 |
2.2.2.4 CONSTANT_Long_info
项目 | 类型 | 描述 |
---|
tag | u1 | 值为5 | bytes | u8 | 按照高位在前存储的long值 |
2.2.2.5 CONSTANT_Double_info
项目 | 类型 | 描述 |
---|
tag | u1 | 值为6 | bytes | u8 | 按照高位在前存储的double值 |
2.2.2.6 CONSTANT_Class_info
项目 | 类型 | 描述 |
---|
tag | u1 | 值为7 | index | u2 | 指向全限定名常量项的索引 |
2.2.2.7 CONSTANT_String_info
项目 | 类型 | 描述 |
---|
tag | u1 | 值为8 | index | u2 | 指向字符串字面量的索引 |
2.2.2.8 CONSTANT_Fieldref_info
项目 | 类型 | 描述 |
---|
tag | u1 | 值为9 | index | u2 | 指向声明字段的类或者接口描述符CONSTANT_Class_info的索引项 | index | u2 | 指向字段描述符CONSTANT_NameAndType的索引项 |
2.2.2.9 CONSTANT_Methodref_info
项目 | 类型 | 描述 |
---|
tag | u1 | 值为10 | index | u2 | 指向声明方法的类或者接口描述符CONSTANT_Class的索引项 | index | u2 | 指向名称及类型描述符CONSTANT_NameAndType的索引项 |
2.2.2.10 CONSTANT_InterfaceMethodref_info
项目 | 类型 | 描述 |
---|
tag | u1 | 值为11 | index | u2 | 指向声明方法的接口描述符CONSTANT_Class的索引项 | index | u2 | 指向名称及类型描述符CONSTANT_NameAndType的索引项 |
2.2.2.11 CONSTANT_NameAndType_info
项目 | 类型 | 描述 |
---|
tag | u1 | 值为12 | index | u2 | 指向该字段或方法名称常量项的索引 | index | u2 | 指向该字段或方法描述符常量项的索引 |
2.2.2.12 CONSTANT_MethodHandle_info
项目 | 类型 | 描述 |
---|
tag | u1 | 值为15 | reference_kind | u1 | 值必须在1至9之间[1-9]它决定了方法句柄的类型。方法句柄类型的值表示方法句柄的字节码行为 | reference_index | u2 | 值必须是对敞亮吃的有效索引 |
2.2.2.13 CONSTANT_MethodType_info
项目 | 类型 | 描述 |
---|
tag | u1 | 值为16 | descriptor_index | u2 | 值必须是对常量池的有效索引,常量池在该索引处的项必须是CONSTANT_Utf8_info结构,表示方法的描述符 |
2.2.2.14 CONSTANT_Dynamic_info
项目 | 类型 | 描述 |
---|
tag | u1 | 值为17 | bootstrap_method_attr_index | u2 | 值必须是对当前Class文件中引导方法表的bootstrap_methods[]数组的有效索引 | name_and_type_index | u2 | 值必须是对当前常量池的有效索引,常量池在该索引处的项必须是CONSTANT_NameAndType_info结构,表示方法名和方法描述符 |
2.2.2.15 CONSTANT_InvkoeDynamic_info
项目 | 类型 | 描述 |
---|
tag | u1 | 值为18 | bootstrap_method_attr_index | u2 | 值必须是对当前Class文件中引导方法表的bootstrap_methods[]数组的有效索引 | name_and_type_index | u2 | 值必须是对当前常量池的有效索引,常量池在该索引处的项必须是CONSTANT_NameAndType_info结构,表示方法名和方法描述符 |
2.2.2.16 CONSTANT_Module_info
| 项目 | 类型 | 描述 |
|