常量池
主、次版本号之后的就是常量池入口,常量池可以比喻为Class
文件的资源仓库,它是Class
文件结构中
与其他项目关联最多的数据,通常也是占用Class
文件空间最大的数据项目之一。
常量池中的常量的数量是不固定的,因此在常量池的入口需要一项u2
类型的数据,代表常量池容量计数器
(constant_pool_count
)。这个容量不是从0开始计数,而是从1开始。因此常量的数量 = constant_pool_count
- 1。
目的是让某些指向常量池的索引值的数据在特定情况下可以表达“不引用任何一个常量池项目”的含义(把索引值设置为0)。
常量池的组成
常量池中主要存放两大类常量
字面量(
Literal
)字面量比较接近
Java
语言层面的常量概念,如文本字符串、被声明为final
的常量值等。符号引用(
Symbolic References
)符号引用属于编译原理方面的概念,主要包括
- 被模块导出或者开发的包(
Package
) - 类和接口的全限定名(
Fully Qualified Name
) - 字段的名称和描述符(
Descriptor
) - 方法的名称和描述符
- 方法句柄和方法类型(
Method Handle
、Method Type
、Invoke Dynamic
) - 动态调用点和动态常量(
Dynamically-Computed Call Site
、Dynamically-Computed Constant
)
- 被模块导出或者开发的包(
Class
文件中不会保存各个方法、字段最终在内存中的布局信息,这些字段、方法的符号引用不经过虚拟机
在运行期转换的话是无法得到真正的内存入口地址的,当虚拟机做类加载时,将会从常量池获得对应的符号引用,
再在类创建时或运行时解析、翻译到具体的内存地址中。
常量池中的每一项都是一个表,表结构起始的第一个位是个u1
类型的标志位(tag
),代表着当前常量属于
哪种常量类型。(每个表的结构都不一样)
ps
Class
文件中方法、字段等都需要引用CONSTANT_Utf8_info
型常量来描述名称。所以CONSTANT_Utf8_info
型常量
的最大长度就是Java
中方法、字段名的最大长度。这里最大长度就是length
的最大值,既u2
类型能表达的最大值
65535。所以Java
程序无法定义超过64KB
英文字符的变量或方法,会无法编译。