【JVM从入门到放弃】2.常量池中的常量

常量池中主要存放两大类常量: 字面量(Literal)和符号引用(Symbolic References)。

  • 字面量类似 Java 的常量, 如文本字符串、被声明为 final 的常量值等
  • 符号引用主要包括: 类和接口的全名、字段的名称和描述符、方法的名称和描述符等

Java 代码在进行编译的时候, 并不像 C 和 C++那样有链接这一步骤, 而是在 JVM 进行类加载的时候进行动态连接。在 class 文件中并不知道各个方法、字段最终在内存中的地址。当 JVM 加载类时, 会从常量池中获得对应的符号引用, 再把符号引用转换成具体的内存地址。

常量池中每一项常量都是一个表, 截止到 JDK21, 常量池中有 17 种不同类型的常量。每一个常量表结构的第一位是个 u1 类型的标志位, 代表着当前常量属于哪种常量类型。这 17 种常量类型各自有着完全独立的数据结构。

类型标志(十进制)说明
CONSTANT_Utf81UTF-8 编码的字符串
CONSTANT_Integer3整型字面量
CONSTANT_Float4浮点型字面量
CONSTANT_Long5长整型字面量
CONSTANT_Double6双精度浮点型字面量
CONSTANT_Class7类或接口的符号引用
CONSTANT_String8字符串类型字面量
CONSTANT_Fieldref9字段的符号引用
CONSTANT_Methodref10类中方法的符号引用
CONSTANT_InterfaceMethodref11接口中方法的符号引用
CONSTANT_NameAndType12字段或方法的部分符号引用
CONSTANT_MethodHandle15方法句柄
CONSTANT_MethodType16方法类型
CONSTANT_Dynamic17动态计算常量
CONSTANT_InvokeDynamic18动态方法调用点
CONSTANT_Module19模块
CONSTANT_Package20一个模块中开放或者导出的包

我们解析一下上一篇文章中 ClassFileDemo.class 文件中的常量池。

#1

最开始的是常量池索引为 1 的常量, 它的标志位是 0x0A(十进制 10), 是一个 CONSTANT_Methodref 类型的常量, CONSTANT_Methodref 的结构如下:

常量项目类型描述
CONSTANT_Methodreftagu1值为 10
-indexu2指向声明方法的类描述符 CONSTANT_Class 的索引项
-indexu2指向名称及类型描述符 CONSTANT_NameAndType 的索引项

两个 index 的值分别是 0x0002 和 0x0003。

#2

接下来是索引为 2 的常量, 它的标志位是 0x07(十进制 7), 是一个 CONSTANT_Class 类型的常量, CONSTANT_Class 的结构如下:

常量项目类型描述
CONSTANT_Classtagu1值为 7
-indexu2指向全限定名常量项的索引

它只有一个 index, 值是 0x0004。

#3

接下来是索引为 3 的常量, 它的标志位是 0x0C(十进制 12), 是一个 CONSTANT_NameAndType 类型的常量, CONSTANT_NameAndType 的结构如下:

常量项目类型描述
CONSTANT_NameAndTypetagu1值为 12
-indexu2指向该字段或方法名称常量项的索引
-indexu2指向该字段或方法描述符常量项的索引

两个 index 的值分别是 0x0005 和 0x0006。

#4

接下来是索引为 4 的常量, 它的标志位是 0x01(十进制 1), 是一个 CONSTANT_Utf8 类型的常量, CONSTANT_Utf8 的结构如下:

常量项目类型描述
CONSTANT_Utf8tagu1值为 1
-lengthu2UTF-8 编码的字符串占用的字节数
-bytesu1长度为 length 的字符串

length 为 0x0010 (十进制 16), 接下来的 16 个字节就是 utf8 编码的字符串: 0x6A6176612F6C616E672F4F626A656374, 随便找 1 个 16 进制转 utf8 的工具解码一下, 得到字符串"java/lang/Object":

#5

接下来是索引为 5 的常量, 它的标志位是 0x01(十进制 1), 也是一个 CONSTANT_Utf8 类型的常量, length 为 0x006 (十进制 6), 接下来的 6 个字节就是 utf8 编码的字符串: 0x3C696E69743E, 解码后得到字符串"<init>"。

#6

接下来是索引为 6 的常量, 同样是一个 CONSTANT_Utf8 类型的常量, length 为 0x003 (十进制 3), 接下来的 3 个字节就是 utf8 编码的字符串: 0x282956, 解码后得到字符串"()V"。

整理一下前 6 个常量:

索引类型描述
#1CONSTANT_Methodref#2, #3类中方法的符号引用
#2CONSTANT_Class#4类或接口的符号引用
#3CONSTANT_NameAndType#5, #6字段或方法的部分符号引用
#4CONSTANT_Utf8java/lang/ObjectUTF-8 编码的字符串
#5CONSTANT_Utf8<init>UTF-8 编码的字符串
#6CONSTANT_Utf8()VUTF-8 编码的字符串

与使用 javap 解析的结果一致:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值