jvm中的常量池有三种:字符串常量池、class常量池、运行时常量池。
字符串常量池
jdk7.0以后(包括现在最新的jdk8),字符串常量池存在于jvm堆中(这与运行时常量池不同)。
既然是在堆中,字符串常量池里存放的自然是“对象”。每次字符串常量池返回给用户的都是这个对象的引用地址。
在java中字符串的创建一直有两种方式,一种是new出来,这种就是创建一个新的字符串对象。
第二种是直接引号赋值,这种会先在常量池里寻找是否有对应的字符串对象,如果有,就返回该对象的引用地址,如果没有则会先在字符串常量池中创建该对象然后再返回引用地址。
class常量池
每一个class文件中都有class常量池,既然是文件中的,那么自然此时的常量池是“静态的”(虽然还是叫池会给人一种在内存中的感觉,可实际上所谓的class常量池,就是class文件里面的具体字节码)。
在class文件中,常量池字节码顺序仅次于魔数和版本号之后。
整个常量池字节码由两部分组成:常量池数量、常量池数组。
常量池数量从1开始计数,其代表了常量池中常量元素的个数。所以假设常量池数量换算成十进制是51,那么实际上就有50个常量元素。
常量数组中只能存11种常量元素,每种常量元素在常量数组中的具体字节码结构都不尽相同。
这11种元素里面,除了整数、字符串等字面量常量元素外,还有包括类的方法信息、接口信息、类中属性信息等各种符号引用。
常量数组中的每一项元素都由两部分组成:tag标识位,和具体元素内容。每一种元素都有它独有的标识位。
运行时常量池
上面讲的class文件里的常量池字节码,在类加载过程的第一个阶段“加载”阶段中,class文件中的常量池字节码会被加载到内存里,也就是加载到运行时常量池中。
所以,所有的class常量池,最后都会被加载到运行时常量池中。
运行时常量池在jdk1.6时放在方法区中,jdk1.7放在堆内存中,jdk1.8放在元空间中。
这个元空间类似于以前的“永久代”,但区别是元空间不在虚拟机中,而使用的是“本地内存”。