| 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
项目 | 类型 | 描述 |
---|---|---|
tag | u1 | 值为19 |
name_index | u2 | 值必须是对常量池的有效索引,常量池在该索引处的项必须是CONSTANT_Utf8_info结构,表示模块名称 |
2.2.2.17 CONSTANT_Package_info
项目 | 类型 | 描述 |
---|---|---|
tag | u1 | 值为19 |
name_index | u2 | 值必须是对常量池的有效索引,常量池在该索引处的项必须是CONSTANT_Utf8_info结构,表示包名称 |
3. 查看常量池表
如果我们使用文本编辑器打开某个Class文件,那么你见到的场景大概是这样的:
除了魔数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命令,观察一下它的常量池表是什么样的。它的常量池表截图如下:
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"产生关联的呢?这和对象的初始化有关,具体的字节码在方法中:
注意看Code的第17 和19行。查询字节码指令可知,ldc指令的含义是’将int、float、或String型常量值从常量池中推送至栈顶’ putfied指令的含义是’为指定类的实例field赋值’,查询常量池表可知,#6对应的值为字符串"dafasoft"。在执行过这两条指令后,我们才完成了对String变量test3的赋值。
3.2 示例二:this.testFun();
本次面试答案,以及收集到的大厂必问面试题分享:
过这两条指令后,我们才完成了对String变量test3的赋值。
3.2 示例二:this.testFun();
本次面试答案,以及收集到的大厂必问面试题分享:
[外链图片转存中…(img-CquwyqOf-1714482476099)]