字符串池、常量池(运行时常量池、Class常量池)、intern

重点:

  • Class 常量池 是编译期生成的 Class 文件中的常量池
  • 运行时常量池 是 Class 常量池 在运行时的表示形式
  • 字符串常量池 是缓存字符串的,全局共享,它保存的是 String 实例对象的引用

Class 常量池

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

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

通过 javap 命令可以看到 Class 文件的常量池部分。

运行时常量池

运行时常量池(Runtime Constant Pool)是方法区的一部分,它是 Class 文件中每一个类或接口的常量池表的运行时表示形式。Class 常量池中存放的编译期生成的各种字面量和符号引用,将在类加载后进入方法区的运行时常量池中存放。

方法区与 Java 堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态常量、即时编译器编译后的代码等数据。虽然 Java 虚拟机规范把方法区描述为堆的一个逻辑部分,但是它却有一个别名叫 Non-Heap(非堆)。目的应该是与 Java 堆区分开来。

字符串常量池

字符串常量池是用来缓存字符串的。对于需要重复使用的字符串,每次都去 new 一个 String 实例,无疑是在浪费资源,降低效率。所以,JVM 一般会维护一个字符串常量池,它是全局共享的,你可是把它看成是一个 HashSet。需要注意的是,它保存的是堆中字符串实例的引用,并不存储实例本身。

String.intern()

查找当前字符串常量池是否存在该字符串的引用,如果存在直接返回引用;如果不存在,则在堆中创建该字符串实例,并返回其引用。

在 JDK 1.6,常量池是在永久代中的,和 Java 堆是完全分开来的区域

在 JDK 1.7, 常量池在堆中