String不可变性由final类、private final字段及所有修改方法返回新对象三重机制保障,支撑常量池复用、线程安全、hashCode缓存及安全性等核心机制。

直接从原理出发学,别背结论。面试官想看的不是你记住“==比较地址、equals比较内容”,而是你能说清为什么String要设计成不可变、为什么常量池能复用、为什么new出来的对象不在池里。
抓住三个核心锚点
所有String面试题都绕不开这三点:
- 不可变性:底层char[](JDK8前)或byte[](JDK9+)被final修饰,所有修改操作(concat、replace、substring等)都返回新对象,原对象不动;这是线程安全和常量池复用的前提。
- 字符串常量池:JDK7起移入堆内存,字面量("abc")自动入池,new String("abc")一定在堆,调用intern()才可能进池——关键看运行时是否已存在相同内容。
- == 和 equals 的本质区别:==永远比内存地址(引用是否指向同一块空间),equals重写后先判地址再逐字符比内容;equals返回true,hashCode必须一致——这是HashMap能正常工作的契约。
用代码反推 JVM 行为
不靠记忆,靠验证。写几段对比代码,然后看结果倒推机制:
- "a" + "b" → 编译期优化为"ab",进常量池;"a" + s(s是变量)→ 运行期拼接,走StringBuilder,结果在堆。
- new String("ab").intern():若池中无"ab",则把堆中对象引用存入池;若有,则返回池中引用——这就是str == "ab"有时为true的原因。
- String s1 = "hello"; s1 += " world":看似修改,实则是s1 = new StringBuilder().append(s1).append(" world").toString(),生成新对象,原"hello"仍在池中。
把常见题还原成内存图
遇到题先画两块区域:常量池(堆里一小块)、Java堆(放new出来的对象)、栈(存变量引用)。例如:
立即学习“Java免费学习笔记(深入)”;
- String a = "x"; String b = "x"; → a、b都指向常量池同一地址 → a == b为true。
- String c = new String("x"); → 常量池已有"x",c指向堆中新对象 → a == c为false,但a.equals(c)为true。
- c.intern() → 池中已有"x",返回池中引用 → a == c.intern()为true。
关联实际场景加深理解
脱离业务的原理是空谈:
- 为什么String适合作为HashMap的key?因为不可变 → hashCode稳定 → 散列位置不变 → 不会因内容变化导致get失效。
- 为什么密码不用String而用char[]?String不可变,一旦创建就可能长期留在内存(尤其常量池),而char[]可手动清空,降低泄露风险。
- 为什么大量拼接用StringBuilder不用String?每次+都新建对象,O(n²)时间+频繁GC;StringBuilder内部char[]可扩容复用,O(n)。


















