Java类文件结构

四、常量池

紧接着主次版本号之后的是常量池入口, 常量池可以理解为Class文件之中的资源仓库, 它是Class文件结构中与其他项目关联最多的数据类型, 也是占用Class文件空间最大的数据项目之一, 同时它还是在Class文件中第一个出现的表类型数据项目.

由于常量池中常量的数据是不固定的, 所以在常量池的入口需要放置一项u2类型的数据, 代表常量池容量计数值. 与Java中语言习惯不一样的是, 这个容量计数器是从1而不是从0开始的, 如下图所示, 常量池容量是0x004E, 值为78, 这就代表常量池中有78项常量, 索引值范围为1-78.

常量池中主要存放两大类常量: 字面量(Literal)和符号引用(Symbolic References). 字面量比较接近于Java语言层面的常概念, 如文本字符串, 声明为final的常量值等. 而符号引用则属于编译原理方面的概念,包括了下面三类常量:

  • 类和接口的全限定名(Fully Qualified Name)
  • 字段的名称和描述符(Descriptor)
  • 方法的名称和描述符

Java代码在进行javac编译的时候,并不像C和C++那样有”连接”这一步骤, 而是在虚拟机加载Class文件的时候进行动态连接. 也就是说,在Class文件中不会保存各个方法,字段的最终内存布局信息, 因此这些字段, 方法的符号引用不经过运行期转换的话无法得到真正的内存入口地址, 也就无法直接被虚拟机使用. 当虚拟机运行时, 需要从常量池获得对应的符号引,再在类创建时或运行时解析,翻译到具体的内存地址之中.

常量中的每一项数据都是一个表类型的结构,每个表类型结构的第1个字节是一个u1数据, 用来标识常量的类型, 而后面的部分则取决于它是什么类型,因为不同的类型的常量的结构是不同的. 总共有十几种常量类型,所以对于它的解析是相对要耗时一些的.