字符串常量池存在是为了节省内存和提升性能,利用字符串不可变性实现相同字面量共享同一对象;JDK7+起位于堆内存中,受GC管理且可动态扩容;触发方式为:双引号字面量自动入池,new String()在堆创建不入池(但字面量部分仍入池),intern()手动将堆中字符串引用加入池并返回池中引用。

回答字符串常量池面试题,关键不是背定义,而是讲清三点:它为什么存在、它在哪、它怎么被触发和影响。面试官真正想确认的是你是否理解 JVM 对字符串的优化逻辑,以及能否结合代码判断对象归属和 ==/equals 行为。
说清楚设计意图:省空间 + 提性能
字符串是 Java 中最常用的对象类型,大量重复内容(比如配置项、HTTP 请求路径、JSON 字段名)如果每次 new 都分配堆内存,会快速消耗资源。常量池本质是一个“去重缓存”——利用字符串不可变性(immutable),让相同字面量共享同一份内存。这既减少 GC 压力,也让 == 比较能安全用于字面量间判等(因为引用相同)。
定位位置:堆里的一块专用区域(JDK 7+)
别再说“方法区”或“永久代”。从 JDK 7 开始,字符串常量池明确移到堆内存中(不是栈,也不是元空间)。这意味着:
- 它受堆大小参数(-Xmx)控制,可动态扩容;
- 里面的字符串对象和其他普通对象一样,能被垃圾回收(前提是没有任何强引用,包括池内引用本身);
- 不再受限于 PermGen 内存溢出的老问题。
讲明白触发方式:字面量自动进池,new 不进,intern 可手动入池
不同创建方式对常量池的影响必须分清:
立即学习“Java免费学习笔记(深入)”;
- String s = "abc" → JVM 编译期识别字面量,直接查池、复用或新建并入池;
- String s = new String("abc") → 总是在堆上新建对象;若池中无"abc",还会额外在池中放一份字面量(即共2个对象);
- s.intern() → 检查池中是否有内容相同的字符串,有则返回池中引用,没有则将当前字符串(JDK 7+ 是引用,非复制)加入池并返回。
举一个能体现理解深度的例子
比如这段代码:
String a = new String("ab");String b = new String("ab");
System.out.println(a == b); // false
System.out.println(a.intern() == b.intern()); // true
System.out.println(a == a.intern()); // false(a 是堆对象,intern 返回池中引用)
能准确解释每行结果,就说明你真懂常量池的边界和作用机制。


















