Java中String是否进常量池取决于创建方式:双引号字面量(含编译期确定的拼接)默认入池并复用;new String()总在堆新建对象,与池无关;intern()可手动将运行时字符串加入池并返回池中引用。

Java 中 String 对象是否进常量池、能否被重用,取决于创建方式和 JVM 版本,不是“写了字符串就自动进池”。掌握这个逻辑,才能真正控制内存和避免 == 判断出错。
双引号字面量:默认走常量池
用 String s = "hello" 这种方式声明的字符串,JVM 会在编译期或类加载时将其放入字符串常量池(前提是内容确定且无运行时拼接)。后续相同字面量会复用池中对象。
- 例如:
String a = "abc"; String b = "abc";→a == b返回 true - 注意:编译期可确定的字符串拼接(如
"ab" + "c")也会被优化为字面量,进入常量池 - 但含变量的拼接(如
"ab" + someVar)结果在运行时生成,不会进池,除非手动调用intern()
new String(...):堆中新建,与池无关
new String("hello") 总是在堆内存中创建一个全新对象,即使常量池里已有相同内容。它和池中对象是两个独立实例。
- 例如:
String a = "hello"; String b = new String("hello");→a == b为 false,但a.equals(b)为 true - JDK7+ 中,
new String("hello")内部仍会先检查并确保常量池有 "hello"(不一定会放入,但字面量已存在),但返回的是堆中新对象的引用
intern():主动把字符串“拉进”常量池
intern() 是一个 native 方法,作用是“查池—有则返引用,无则入池再返引用”。它让运行时生成的字符串也能享受池化复用。
立即学习“Java免费学习笔记(深入)”;
- 例如:
String s = new String("world").intern();→ 此时s指向常量池中的 "world",和String t = "world"的t是同一个对象 - 注意:频繁调用
intern()可能导致常量池膨胀(尤其 JDK8+ 默认大小 60013),建议只对高频、重复、生命周期长的字符串使用 - 若字符串已存在于池中,
intern()不会复制,直接返回池中引用,开销极小
JDK7+ 常量池在堆里,不是永久代
从 JDK7 开始,字符串常量池从方法区(永久代)移到了堆内存,这是关键变化:
- 池中存储的是堆中字符串对象的引用,不再是对象副本本身,节省空间
- 常量池可被 GC 回收(当字符串不再被任何地方引用时),降低 OOM 风险
- 这意味着:池中引用的对象如果被回收,对应条目也会清理;而 JDK6 的永久代池一旦满了就容易抛
OutOfMemoryError: PermGen space


















