这篇文章将为大家详细讲解有关如何理解Java Class文件常量池,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。
Class文件的存在使得不同语言编写的程序都可以运行在Java虚拟机上,只需要这些语言经过编译器编译后的Class文件符合Java虚拟机定义的规范,Java虚拟机就可以加载执行这些Class文件。如下图所示:
Class文件是一组以8位字节为基础单位的二进制流,各个数据项目严格按照顺序紧凑地排列在Class文件中,当遇到需要占用8个字节以上空间的数据是,则按照大端序的方式分割成若干个8位字节进行存储。
Class文件中只存在两种数据类型:
-
无符号数 -
表
无符号数属于基本数据类型,以u1、u2、u4、u8分别表示1个、2个、4个和8个字节的无符号数,无符号数可以用来描述数字、索引引用、数量值或者按照UTF-8编码构成的字符串值。
表是由无符号数和其他表组成的数据结构,所有的表都以_info结尾。
当在描述一个可变长度的类型数据时,通常会采用一个容量计数器和若干个数据项的格式。
public class ClassTest {
private int m;
private int inc() {
return m + 1;
}
}
下面我们会通过上面这段代码来分析Class文件的内容。
上面这张图是经过编译后的Class文件中的内容
魔数(magic)与版本号
Class文件开头固定的4个字节为魔数,唯一作用就是用来确定这个文件是否是一个能被虚拟机接收的class文件。Java的魔数固定为0xCAFEBABE,接下去的两个字节代表次要版本号,再下去的两个字节是主版本号,主版本号为0x0034(十进制是52,也就是JDK1.8),高版本的JDK能够运行以前版本的Class文件,但是不能运行以后版本的Class文件,通俗一点将就是向下兼容。
常量池
走过了魔数和版本,接下去是Class文件中最关键的部分常量池,常量池由一个计数池和具体的常量项来组成,在我们代码中常量池数量为0x0013(十进制是19),关于常量池的计数池有一个比较特殊的地方就是他是从1开始计数的,也就是说如果我们计数池的值是19,实际上是只有18个常量项。
常量池中主要存放两大类常量:
-
字面量 -
符号引用
字面量主要指的是文本字符串、声明为final的常量值等
符号引用主要包含三类常量:
-
类和接口的全限定名 -
字段的名称和描述符 -
方法的名称和描述符
Java代码在编译的时候不存在连接时,也就是Class文件中不会保存各个方法、字段的最终内存布局信息,这些字段、方法的符号引用如果在运行期不进行转换则得不到真正的内存入口地址,所以在虚拟机运行时,需要从常量池获得对应的符号引用,在类创建和运行时解析翻译到具体的内存地址中。
目前常量池中主要有以下表项:
这些表都会有一个固定的字段也就是开始的第一个字节都是一个标志位代表相应的类型,如上图。
大家可以通过javap -verbose xxx.class列出文件字节码的内容
通过比较javap -verbose常量池的项的索引和我们class文件二进制的表示可以发现是一一对应的。
关于如何理解Java Class文件常量池就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。
原创文章,作者:carmelaweatherly,如若转载,请注明出处:https://blog.ytso.com/208271.html