天天看点

常量池 字符串常量池 class常量池 运行时常量池详解

本文先简述下常量池随JDK版本更替而产生的变化,后介绍三种常量池的区别,可按需观看.

JDK版本迭代造成的变化

首先,众所周知,“常量池属于方法区的一部分”,这句话对于JDK6之前可能完全准确,但在JDK7之后就会有人有不同的理解了.

这里以Hotspot虚拟机来进行说明.

JDK6及其之前,方法区通过永久代进行实现,而常量池属于方法区的一部分也存在于永久代中,此时方法区甚至可以等同于永久代,因此说常量池是方法区的一部分是完全没有问题的.

而在JDK7中,Hotspot将原本存储于永久代中的字符串常量池和静态变量移入堆中存储.但方法区中的其余内容依旧存储于永久代中(ps:永久代也是堆内的一片连续空间,因此此时二者其实也还都在堆中)

JDK8彻底废除永久代,改用元空间实现方法区,并将方法区中其余内容全部移入元空间(元空间靠堆外内存实现),也就是说,此时常量池和静态变量存储于堆中,而方法区其余内容则是存储于堆外内存

故在JDK8中,方法区其实已经被拆分了,常量池逻辑上属于方法区,而实际存储则如上所述.

三大常量池的区别

  1. class常量池:存储类的信息与字面量(和字面量引用区分开,字面量是int a = 1,String str = “abc”里的1和”abc”)
  2. 运行时常量池:当类加载到内存后(详见类加载过程),class常量池中的内容就会全部存放到运行时常量池(因此运行时常量池也是一个类一个),但运行时常量池中的内容可以在运行时动态添加(最明显的就是字符串)
  3. 字符串常量池:存放字符串的引用,实际的值存储在运行时常量池中.

    因此,找字符串就先在字符串常量池中找,找不到再新建然后添加引用到字符串常量池中,而找其余字面量则是去对应类的运行时常量池中找,基础数据类型就直接比较,否则就比较地址.

证明如下图

常量池 字符串常量池 class常量池 运行时常量池详解

运行结果ture,false.

因为a,b和A.a,A.b属于不同类,也存储于不同的运行时常量池中,故其地址也不同,但根据上述比较关系,a和A.a直接比较值故返回true,而b和A.b则比较地址,二者存储的运行时常量池都不同,地址一定不同,故返回false.