Java字符串常量池是堆内存中的哈希表,用于缓存字面量和intern()字符串以节省内存;字面量自动入池,new String()总新建堆对象,intern()手动归池,JDK 1.7+后池位于堆中并受GC管理。

Java字符串常量池(String Constant Pool)本质上是一个**堆内存中的哈希表结构**,专门用于缓存字符串字面量和显式调用 intern() 的字符串对象,目的是避免重复创建内容相同的字符串,提升性能、节省内存。
字符串字面量自动入池
当你写 String s = "abc"; 时,JVM不会直接在堆中新建对象。它会:
- 先查字符串常量池中是否已有内容为
"abc"的字符串引用; - 如果有,直接返回该引用(即指向池中已存在的对象);
- 如果没有,则在堆中创建一个新的
String对象,并将它的引用存入常量池,再返回这个引用。
所以 String a = "abc"; String b = "abc"; 中,a == b 为 true —— 它们指向同一个堆对象。
new String() 总是在堆中新建对象
使用 new String("abc") 时,无论池中是否存在相同内容:
立即学习“Java免费学习笔记(深入)”;
- JVM一定在堆中创建一个新对象;
- 但仍然会检查常量池:若池中无
"abc",则先将字面量"abc"加入池(注意:只是把字面量本身入池,不是 new 出来的那个对象); - 最终返回的是堆中新对象的引用,与池中对象无关。
因此 String a = "abc"; String b = new String("abc"); 中,a == b 是 false,尽管内容相同。
intern() 方法是手动“归池”的关键
intern() 的作用是:确保当前字符串(无论怎么创建)在常量池中有且仅有一个对应引用。
- 调用
s.intern()时,JVM检查池中是否有内容相同的字符串引用; - 有,则直接返回池中那个引用;
- 没有,则将当前字符串对象(或其内容)加入池,并返回该引用。
注意:JDK 1.7+ 后,intern() 不再复制字符串,而是把堆中已存在的字符串对象引用存入池中(池本身在堆里),所以效率更高、更省内存。
常量池位置随JDK版本变化
这个细节影响GC和内存调优:
- JDK 1.6 及以前:字符串常量池在方法区(永久代);
- JDK 1.7:移到堆中(但池中存的是堆对象的引用);
- JDK 1.8+:永久代被元空间(Metaspace)取代,而字符串常量池始终保留在堆中。
这意味着从 JDK 1.7 起,字符串常量池的大小可由 -XX:MaxHeapSize 影响,也受 GC 管理——当堆内存紧张时,未被引用的池中字符串可能被回收(前提是无强引用指向它)。










