这是我参与8月更文挑战的第29天,活动详情查看:8月更文挑战
🔸一、常量池总数
-
常量池大小(cp_info_count):常量池是class文件中第一个出现的变长结构。既然是池,就有大小,常量池大小由两个字节表示(u2)。
-
假设常量池大小为n,常量池真正有效的索引是1
n-1。如果constant pool_count等于10,constant_pool数组的有效索引值是19。0属于保留索引,可供特殊情况使用。
常量池总数数据结构
🔺二、常量池【静态常量池(很多时候我们说的静态常量池指的就是class文件中的常量池)】
- Java虚拟机指令不依赖于类、接口、类实例或数组的运行时布局,而是依赖常量池表中的符号信息
- 如创建对象的new指令,需要指定对象的类型描述符,new指令的操作数的值为该类型描述符对应的常量在常量池中的索引,虚拟机将根据常量信息到方法区寻找对应的class元数据。
常量池中主要存放两大类常量:
-
字面量(Literal) 字符串(UTF-8)、被声明为final的常量值(整数值、浮点)等
-
符号引用(Symbolic References)
类和接口的全限定名(Fully Qualified Name)
字段的名称和描述符(Descriptor)
方法的名称和描述符
方法句柄和方法类型(Method Handle、Method Type、Invoke Dynamic)
动态调用点和动态常量(Dynamically-Computed Call Site、Dynamically-Computed Constant)
1. 常量池数据结构
- 常量池是一个数组。里面每一个项为一个具体的常量
-
常量池中的每一项为一个具体的常量,其数据结构如下
-
根据《Java虚拟机规范》规定,常量池表中所有常量项的结构都包含一个tag项,tag值用于标志一个常量是哪种常量结构。只有根据tag确定常量的结构,才能根据常量结构计算常量所占用的字节数。
2. 根据tag的不同 ,JDK8中常量具体分为14种
| 常量类型 | tag | 描述 |
|---|---|---|
| CONSTANT_Class_info | 7 | 类或接口的符号引用 |
| CONSTANT_Fieldref_info | 9 | 字段的符号引用 |
| CONSTANT_Methodref_info | 10 | 类中方法的符号引用 |
| CONSTANT_InterfaceMethodref_info | 11 | 接口中方法的符号引用 |
| CONSTANT_String_info | 8 | 字符串类型字面量 |
| 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 | 表示一个动态方法调用点 |
3. 字段描述符
-
字段描述符(field descriptor),用来表示类、实例或局部变量
-
符号列表为:
| 字符 | 类型 | 含义 |
|---|---|---|
| B | byte | 有符号的字节型数 |
| ------------- | --------- | ----------------------------------------- |
| C | char | 基本多文种平面中的Unicode字符码点,UTF-16编码双精度浮点数单精度浮点数 |
| D | double | 双精度浮点数 |
| F | float | 单精度浮点数 |
| I | int | 整型数 |
| J | long | 长整数 |
| L ClassName ; | reference | ClassName 类的实例 |
| S | short | 有符号短整数 |
| Z | boolean | 布尔值true/false |
| [ | reference | 一个一维数组 |
-
例如:
-
描述int实例变量的描述符是I
-
object类型的实例,其描述符是Ljava/lang/object;
-
三维数组double d[][][]类型的实例变量,其描述符为[[[D
4. 方法描述符
- 方法描述符(method descriptor)包含0个或多个参数描述符(parameter descriptor)以及个返回值描述符(return descriptor)参数描述符表示该方法所接受的参数类型,如果该方法有返回值的话,那么返回值描述符则表示该方法的返回值类型
- 实例方法除了传递自身定义的参数,还需要额外传递参数this ,但是这一点不是由方法描述符来表达,参数this的传递由Java虚拟机中调用实例方法所使用的指令来实现。
- 类方法和实例方法描述符都是一样
例如:
方法为:Object m(int i, double d, Thread t) { .. }
描述符为:(IDLjava/lang/Thread;)Ljava/lang/Object
实例方法除了递自身定义的参数,还需要额外传递参数this ,但是这一点不是由方法描述符来表达,参数this的传递由Java虚拟机中调用实例方法所使用的指令来实现
5. CONSTANT_Class_info
CONSTANT_Class_info {
u1 tag;
u2 name_index;
}
解释
l 类、接口、数组、枚举、注解的符号引用
l 一个有效的数组类型描述符中描述的数组,其维度必须小于等于255
l 类中或接口中使用到了其他的类,只有在类中实际使用到了该类时,该类的信息才会在常量池中有对应的CONSTANT_Class_info常量池项;
l 项约束
l u2 name_index:必须是一个CONSTANT_Utf8_info常量,表示类(或者接口)的全限定名
6. CONSTANT_Fieldref_info
CONSTANT_Fieldref_info {
u1 tag;
u2 class_index;
u2 name_and_type_index;
}
解释
- 字段的符号引用
- static final修饰的字面量(即static final修饰的数据类型是String、基本数据类型【不含基本数据类型的包装类】)不会出现Fieldref_info
- 所有使用的字段(含赋值的字段、再其它地方使用的字段、使用了其它类的字段)
项约束
- u2 class_index:指向的常量必须是一个CONSTANT_Class_Info常量,表示当前字段所在的类的类名。
- u2 name_and_type_index:指向的常量必须是一个CONSTANT_NameAndType_info常量,表示当前字段的名字和类型描述符。
7. CONSTANT_Methodref_info
CONSTANT_Methodref_info {
u1 tag;
u2 class_index;
u2 name_and_type_index;
}
解释
- 类中方法的符号引用
- 所有使用的方法(也就是必须调用)
- 默认调用父类无参构造方法
<init>:()V
项约束
- u2 class_index:指向的常量必须是一个CONSTANT_Class_Info常量,且必须是类(而不能是接口),表示当前方法所在的类的类名。
- u2 name_and_type_index:指向的常量必须是一个CONSTANT_NameAndType_info常量,表示当前方法的名字和类型描述符。
8. CONSTANT_InterfaceMethodref_info
CONSTANT_InterfaceMethodref_info {
u1 tag;
u2 class_index;
u2 name_and_type_index;
}
解释
- 接口中方法的符号引用
项约束
- u2 class_index:指向的常量必须是一个CONSTANT_Class_Info常量,且必须是接口类型,表示当前接口方法所属的接口的类名。
- u2 name_and_type_index:指向的常量必须是一个CONSTANT_NameAndType_info常量,表示当前接口方法的名字和。
9. CONSTANT_String_info
CONSTANT_String_info {
u1 tag;
u2 string_index;
}
解释
- 字符串类型字面量
- static final 修饰String数据类型
- 其它的出现的string字面量
项约束
- u2 string_index:值为常量池中某个常量的索引,该索引指向的常量必须是一个CONSTANT_Utf8_info常量。
10. CONSTANT_Integer_info
CONSTANT_Integer_info {
u1 tag;
u4 bytes;
}
解释
整型字面量
- static final 修饰byte、char、short、boolean、int数据类型
- 可用于描述boolean(1,0)、byte(-27
27-1【-128127】)、int、short(-215215-1【-3276832767】)、char(0~216-1【0-65535】) - 非static final修饰,在-32768
32767(即-215215-1,short的范围内)范围,则直接进入字节码指令内部,超出此范围进入直接进CONSTANT_Integer_info常量池
项约束
- u4 bytes:bytes转为10进制数就是这个常量所表示的整型值。
11. CONSTANT_Float_info
CONSTANT_Float_info {
u1 tag;
u4 bytes;
}
解释
-
static final 修饰 float
-
其它的出现的字面量
约束
- u4 bytes:bytes转为10进制数就是这个常量所表示的浮点值。
12. CONSTANT_Long_info
CONSTANT_Long_info {
CONSTANT_Long_info {
u1 tag;
u4 high_bytes;
u4 low_bytes;
}
解释
- 长整形字面量
- static final 修饰 Long
- 其它的出现的字面量
约束
- u4 high_bytes:高32位区
- u4 low_bytes:低32位区
13. CONSTANT_Double_info
CONSTANT_Double_info {
u1 tag;
u4 high_bytes;
u4 low_bytes;
}
解释
-
双精度浮点型字面量
-
static final 修饰 double
-
其它的出现的字面量
约束
- u4 high_bytes:高32位区
- u4 low_bytes:低32位区
14. 字面量和 Fieldref_info的出现的规则
- 字面量:数据类型是String以及基本数据类型(不包含基本数据类型包装类)\
引用类型(非字面量,含基本数据类型的包装类型):\
1——static final修饰的字面量在本类和其它类里面都会以字面量类型的常量出现
2——非static final修饰的字面量在本类以字面量类型的常量出现和Fieldref_info类型的常量出现
3——非static final修饰的字面量在其它类以Fieldref_info类型的常量出现
4——引用类型在本类和其它类里面都会Fieldref_info
5——static final修饰的字面量不会出现Fieldref_info
6——static final修饰的基本数据类型包装类会同时出现Fieldref_info和包装类的字面量常量类型
15. CONSTANT_NameAndType_info
CONSTANT_NameAndType_info {
u1 tag;
u2 name_index;
u2 descriptor_index;
}
解释
- 字段与字段类型或方法与方法类型的符号引用
约束项
- u2 name_index:必须是CONSTANT_Utf8_info结构的常量,表示字段与字段类型或方法与方法类型的的名称。
- 构造方法名称统一使用
- u2 descriptor_index:必须是CONSTANT_Utf8_info结构的常量,表示一个有效的字段描述符或方法描述符。
16. CONSTANT_Utf8_info
CONSTANT_Utf8_info {
u1 tag;
u2 length;
u1 bytes[length];
}
解释
- UTF-8编码字符串
约束
- u2 length:该值指明了bytes[]数组的长度
- u1 bytes[length]:是表示字符串值的byte数组
17. CONSTANT_MethodHandle_info【动态类型语言支持】【认知】
CONSTANT_MethodHandle_info {
u1 tag;
u1 reference_kind;
u2 reference_index;
}
表示方法句柄,这是虚拟机为实现动态调用invokedynamic指令所增加的常量结构。
- u1 reference_kind:取值范围为1~9,包括1和9,表示方法句柄的类型
- u2 reference_index:其值为指向常量池中某个常量的索引
18. CONSTANT_MethodType_info【动态类型语言支持】【认知】
CONSTANT_MethodType_info {
u1 tag;
u2 descriptor_index;
}
-
表示方法类型,与CONSTANT_MethodHandle_info结构一样,也是虚拟机为实现动态调用invokedynamic指令所增加的常量结构。
-
u2 descriptor_index:必须是CONSTANT_Utf8_info结构的常量,指向常量池中的某一CONSTANT_Utf8_info结构的常量。
19. CONSTANT_InvokeDynamic_info【动态类型语言支持】【认知】
CONSTANT_InvokeDynamic_info {
u1 tag;
u2 bootstrap_method_attr_index;
u2 name_and_type_index;
}
表示一个动态方法调用点,即invokedynamic指令用到的引导方法bootstrap method以及引导方法所用到的动态调用名称、参数、返回类型。
- u2 bootstrap_method_attr_index:指向class文件结构属性表中引导方法表的某个引导方法
- u2 name_and_type_index:指向的常量必须是一个CONSTANT_NameAndType_info常量