[java]JVM之运行时常量池里到底有什么(1)

| tag | u1 | 值为5 |
| bytes | u8 | 按照高位在前存储的long值 |

2.2.2.5 CONSTANT_Double_info
项目类型描述
tagu1值为6
bytesu8按照高位在前存储的double值
2.2.2.6 CONSTANT_Class_info
项目类型描述
tagu1值为7
indexu2指向全限定名常量项的索引
2.2.2.7 CONSTANT_String_info
项目类型描述
tagu1值为8
indexu2指向字符串字面量的索引
2.2.2.8 CONSTANT_Fieldref_info
项目类型描述
tagu1值为9
indexu2指向声明字段的类或者接口描述符CONSTANT_Class_info的索引项
indexu2指向字段描述符CONSTANT_NameAndType的索引项
2.2.2.9 CONSTANT_Methodref_info
项目类型描述
tagu1值为10
indexu2指向声明方法的类或者接口描述符CONSTANT_Class的索引项
indexu2指向名称及类型描述符CONSTANT_NameAndType的索引项
2.2.2.10 CONSTANT_InterfaceMethodref_info
项目类型描述
tagu1值为11
indexu2指向声明方法的接口描述符CONSTANT_Class的索引项
indexu2指向名称及类型描述符CONSTANT_NameAndType的索引项
2.2.2.11 CONSTANT_NameAndType_info
项目类型描述
tagu1值为12
indexu2指向该字段或方法名称常量项的索引
indexu2指向该字段或方法描述符常量项的索引
2.2.2.12 CONSTANT_MethodHandle_info
项目类型描述
tagu1值为15
reference_kindu1值必须在1至9之间[1-9]它决定了方法句柄的类型。方法句柄类型的值表示方法句柄的字节码行为
reference_indexu2值必须是对敞亮吃的有效索引
2.2.2.13 CONSTANT_MethodType_info
项目类型描述
tagu1值为16
descriptor_indexu2值必须是对常量池的有效索引,常量池在该索引处的项必须是CONSTANT_Utf8_info结构,表示方法的描述符
2.2.2.14 CONSTANT_Dynamic_info
项目类型描述
tagu1值为17
bootstrap_method_attr_indexu2值必须是对当前Class文件中引导方法表的bootstrap_methods[]数组的有效索引
name_and_type_indexu2值必须是对当前常量池的有效索引,常量池在该索引处的项必须是CONSTANT_NameAndType_info结构,表示方法名和方法描述符
2.2.2.15 CONSTANT_InvkoeDynamic_info
项目类型描述
tagu1值为18
bootstrap_method_attr_indexu2值必须是对当前Class文件中引导方法表的bootstrap_methods[]数组的有效索引
name_and_type_indexu2值必须是对当前常量池的有效索引,常量池在该索引处的项必须是CONSTANT_NameAndType_info结构,表示方法名和方法描述符
2.2.2.16 CONSTANT_Module_info
项目类型描述
tagu1值为19
name_indexu2值必须是对常量池的有效索引,常量池在该索引处的项必须是CONSTANT_Utf8_info结构,表示模块名称
2.2.2.17 CONSTANT_Package_info
项目类型描述
tagu1值为19
name_indexu2值必须是对常量池的有效索引,常量池在该索引处的项必须是CONSTANT_Utf8_info结构,表示包名称

3. 查看常量池表

如果我们使用文本编辑器打开某个Class文件,那么你见到的场景大概是这样的: image.png

除了魔数CAFE BABE 其他的信息阅读起来可能会有很大的困难。好在Oracle为我们提供了一个专门用于分析Class文件字节码的工具:javap。javap的使用方式:

javap -verbose xxxx.class

简单写一个java类Test, 代码如下:

public class Test {
String test = “dafa”;
String test1 = “soft”;
String test3 = “dafasoft”;

public Test() {
}

void Test() {
this.testFun();
}

public void testFun() {
}

public void testFun1() {
}

public void testFun2() {
}

public static void main(String[] args) {
}
}

我们编译后使用javap命令,观察一下它的常量池表是什么样的。它的常量池表截图如下: image.png

javap工具为我们自动加了注释,但实际上如果我们把上面的表结构看完,不加注释也是看明白的 举两个例子:

3.1. 示例一:String test3 = “dafasoft”;

这是我们在java类中定义的字符串字面常量,如何在常量池表中寻找呢?首先,它是一个Field,我们首先寻找Fieldref,上图的表中共有三个Fieldref,我们逐一查找即可。
根据 第2.2.2.8章节的表结构我们知道,Filedref后面的两个值是两个index, 分别指向声明字段的类或者接口描述符CONSTANT_Class_info的索引项指向字段描述符CONSTANT_NameAndType的索引项,比如 #7处的Fieldref对应的值为#9.#40, #9 对应的值为#42, #42对应的值字符串“com/dafasoft/test/Test”; #40对应的值为#14:#12, #14对应的值为字符串test3, #12对应的值为字符串“Ljava/lang/String;”, 这些信息频道一起,我们就可以得出#7处的Fieldref是指向com/dafasoft/test/Test.test3:Ljava/lang/String;处的一个字符引用。
到现在为止,我们已经知道这个类里有一个引用指向com/dafasoft/test/Test.class 的变量test3 ,其类型为String类型,那么它是怎么和它的值"dafasoft"产生关联的呢?这和对象的初始化有关,具体的字节码在方法中: image.png
注意看Code的第17 和19行。查询字节码指令可知,ldc指令的含义是’将int、float、或String型常量值从常量池中推送至栈顶’ putfied指令的含义是’为指定类的实例field赋值’,查询常量池表可知,#6对应的值为字符串"dafasoft"。在执行过这两条指令后,我们才完成了对String变量test3的赋值。
3.2 示例二:this.testFun();

本次面试答案,以及收集到的大厂必问面试题分享:

字节跳动超高难度三面java程序员面经,大厂的面试都这么变态吗?

过这两条指令后,我们才完成了对String变量test3的赋值。
3.2 示例二:this.testFun();

本次面试答案,以及收集到的大厂必问面试题分享:

[外链图片转存中…(img-CquwyqOf-1714482476099)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

  • 21
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值