java虚拟机常量池

常量池通用格式

cp_info {
u1 tag;
u1 info[];
}
1
2
3
4
tag 表示常量项类型,整理如下:

常量类型 值 描述
CONSTANT_Class_info 7 表示类或接口
CONSTANT_Fieldref_info 9 字段信息表
CONSTANT_Methodref_info 10 方法
CONSTANT_InterfaceMethodref_info 11 接口方法
CONSTANT_String_info 8 java.lang.String 类型的常量对象
CONSTANT_Integer_info 3 整型字面量
CONSTANT_Float_info 4 浮点型字面量
CONSTANT_Long_info 5 长整型字面量
CONSTANT_Double_info 6 双精度型字面量
CONSTANT_NameAndType_info 12 名称和类型表
CONSTANT_Utf8_info 1 utf-8 编码的字符串
CONSTANT_MethodHandle_info 15 方法句柄表
CONSTANT_MethodType_info 16 方法类型表
CONSTANT_InvokeDynamic_info 18 动态方法调用点
对应具体类型分析如下:
1、CONSTANT_Class_info

功能: 表示类或接口
格式:

CONSTANT_Class_info {
u1 tag;
u2 name_index;
}
其中:tag 值为7,表示一个 CONSTANT_Class_info 类型
name_index, 必须是对常量池的一个有效索引。 常量池在该索引处的项必须是CONSTANT_Utf8_info 结构, 代表一个有效的类或接口二进制名称的内部形式。
1
2
3
4
5
6
7
8
9
2、CONSTANT_Fieldref_info

功能: 表示字段字面量
格式:

CONSTANT_Fieldref_info {
u1 tag; //9
u2 class_index; //CONSTANT_Fieldref_info 结构的 class_index 项的类型既可以是类也可以是接口。
u2 name_and_type_index;
}
class_index 项的值必须是对常量池的有效索引, 常量池在该索引处的项必须是CONSTANT_Class_info 结构,表示一个类或接口,当前字段或方法是这个类或接口的成员。
name_and_type_index: 项的值必须是对常量池的有效索引, 常量池在该索引处的项必须是 CONSTANT_NameAndType_info 结构,它表示当前字段或方法的名字和描述符。
1
2
3
4
5
6
7
8
9
10
方法符号引用 和 接口方法符号引用结构和 字段字面量 类似,如下:
3、CONSTANT_Methodref_info

功能: 表示方法符号引用
格式:
CONSTANT_Methodref_info {
u1 tag; //10
u2 class_index; //CONSTANT_Methodref_info 结构的 class_index 项的类型必须是类(不能是接口)。
u2 name_and_type_index;
}
1
2
3
4
5
6
7
4、CONSTANT_InterfaceMethodref_info

功能: 表示接口方法符号引用
格式:
CONSTANT_InterfaceMethodref_info {
u1 tag; //11
u2 class_index; //CONSTANT_InterfaceMethodref_info 结构的class_index 项的类型必须是接口
(不能是类)。
u2 name_and_type_index;
}
1
2
3
4
5
6
7
8
5、CONSTANT_String_info

功能: 表示方法符号引用
格式:
CONSTANT_String_info {
u1 tag; //8
u2 string_index;
}
string_index 项的值必须是对常量池的有效索引, 常量池在该索引处的项必须是CONSTANT_Utf8_info 结构,表示一组 Unicode 码点序列,这组 Unicode 码点序列最终会被初始化为一个 String 对象
1
2
3
4
5
6
7
6、CONSTANT_Integer_info、CONSTANT_Float_info

功能: 表示表示 4 字节的整型、浮点型字面量
格式:
CONSTANT_Integer_info {
u1 tag; //3
u4 bytes;
}
CONSTANT_Integer_info 结构的 bytes 项表示 int 常量的值,按照 Big-Endian的顺序存储。

CONSTANT_Float_info {
u1 tag; //4
u4 bytes;
}
CONSTANT_Float_info 结构的 bytes 项按照 IEEE 754 单精度浮点格式.表示 float 常量的值,按照 Big-Endian 的顺序存储。
1
2
3
4
5
6
7
8
9
10
11
12
13
7、CONSTANT_Long_info 、CONSTANT_Double_info

功能:表示 8 字节(long 和 double)的数值常量
注1
在Class 文件的常量池中,所有的 8 字节的常量都占两个表成员(项)的空间。如果一个 CONSTANT_Long_info 或 CONSTANT_Double_info 结构的项在常量池中的索引为 n,则常量池中下一个有效的项的索引为 n+2, 此时常量池中索引为 n+1 的项有效但必须被认为不可用。

格式:
CONSTANT_Long_info {
u1 tag; //5
u4 high_bytes;
u4 low_bytes;
}
CONSTANT_Long_info 结构中的无符号的 high_bytes 和 low_bytes 项用于共同表
示 long 型常量,构造形式为((long) high_bytes << 32) + low_bytes,high_bytes 和 low_bytes 都按照 Big-Endian 顺序存储。

CONSTANT_Double_info {
u1 tag; //6
u4 high_bytes;
u4 low_bytes;
}
CONSTANT_Double_info 结构中的 high_bytes 和 low_bytes 共同按照 IEEE 754
双精度浮点格式 表示 double 常量的值。 high_bytes 和 low_bytes 都按照 Big-Endian 顺序存储。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
8、CONSTANT_NameAndType_info

功能:表示字段或方法(描述其名称和类型)
格式:
CONSTANT_NameAndType_info {
u1 tag; //12
u2 name_index;
u2 descriptor_index;
}

name_index 项的值必须是对常量池的有效索引, 常量池在该索引处的项必须是CONSTANT_Utf8_info 结构,这个结构要么表示特殊的方法名,要么表示一个有效的字段或方法的非限定名(Unqualified Name)。

descriptor_index 项的值必须是对常量池的有效索引, 常量池在该索引处的项必须是CONSTANT_Utf8_info 结构,这个结构表示一个有效的字段描述符 或方法描述符。
1
2
3
4
5
6
7
8
9
10
11
9、CONSTANT_Utf8_info

功能:表示字段或方法
格式:
CONSTANT_Utf8_info {
u1 tag; //1
u2 length;
u1 bytes[length];
}
length 项的值指明了 bytes[]数组的长度(注意,不能等同于当前结构所表示的String 对象的长度), CONSTANT_Utf8_info 结构中的内容是以 length 属性确定长度而不是以 null 作为字符串的终结符。
如果 length 的值为 0x00, 则没有 bytes[length]。

bytes[]是表示字符串值的byte数组, bytes[]数组中每个成员的byte值都不会是0,
也不在 0xf0 至 0xff 范围内。
1
2
3
4
5
6
7
8
9
10
11
12
10、CONSTANT_MethodHandle_info

功能:表示方法句柄
格式:
CONSTANT_MethodHandle_info {
u1 tag; //15
u1 reference_kind;
u2 reference_index;
}
reference_kind 项的值必须在 1 至 9 之间(包括 1 和 9),它决定了方法句柄的类型。方法句柄类型的值表示方法句柄的字节码行为。
1
2
3
4
5
6
7
8
11、CONSTANT_MethodType_info

功能:表示方法类型
格式:
CONSTANT_MethodType_info {
u1 tag; //16
u2 descriptor_index;
}
descriptor_index 项的值必须是对常量池的有效索引, 常量池在该索引处的项必须是CONSTANT_Utf8_info 结构,表示方法的描述符。
1
2
3
4
5
6
7
12、CONSTANT_InvokeDynamic_info

功能:表示方法类型
格式:
CONSTANT_InvokeDynamic_info {
u1 tag; //18
u2 bootstrap_method_attr_index;
u2 name_and_type_index;
}

bootstrap_method_attr_index 项的值必须是对当前 Class 文件中引导方法表的 bootstrap_methods[]数组的有效索引。

name_and_type_index 项的值必须是对当前常量池的有效索引, 常量池在该索引处的项必须是 CONSTANT_NameAndType_info 结构,表示方法名和方法描述。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
举个例子来说明虚拟机常量池的符号引用替换为字节引用过程。 假设有如下Java代码: ``` public class Test { public static void main(String[] args) { String str = "Hello World"; System.out.println(str); } } ``` 在编译该Java代码时,会生成对常量池中的符号引用的调用,如下所示: ``` 0: ldc #2 // String Hello World 1: astore_1 2: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream; 5: aload_1 6: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 9: return ``` 这里的 `ldc` 指令将字符串 "Hello World" 加载到操作数栈中,使用到了常量池中的符号引用。而在实际运行时,虚拟机需要将符号引用替换为字节引用,这个过程称为解析。 假设常量池中的符号引用为: ``` #2 = String #6 // Hello World #3 = Fieldref #7.#8 // java/lang/System.out:Ljava/io/PrintStream; #4 = Methodref #9.#10 // java/io/PrintStream.println:(Ljava/lang/String;)V #6 = Utf8 Hello World #7 = Class java/lang/System #8 = NameAndType #11:#12 // out:Ljava/io/PrintStream; #9 = Class java/io/PrintStream #10 = NameAndType #13:#14 // println:(Ljava/lang/String;)V #11 = Utf8 out #12 = Utf8 Ljava/io/PrintStream; #13 = Utf8 println #14 = Utf8 (Ljava/lang/String;)V ``` 那么解析过程如下: 1. `ldc #2` 指令将常量池中的符号引用 `#2` 解析为字节引用 `Hello World`,并将其加载到操作数栈中。 2. `getstatic #3` 指令将常量池中的符号引用 `#3` 解析为字节引用 `System.out:Ljava/io/PrintStream;`。 3. `aload_1` 指令将 `ldc #2` 指令加载到的字节引用 `Hello World` 存储到局部变量表的第一个位置上。 4. `invokevirtual #4` 指令将常量池中的符号引用 `#4` 解析为字节引用 `println:(Ljava/lang/String;)V`,并调用 `PrintStream.println` 方法。 这样,虚拟机就将常量池中的符号引用替换为了字节引用,完成了解析过程。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值