String不可变性核心在于:对象本身不修改,所有操作均返回新对象;常量池仅对编译期字面量生效;==比较地址,equals()比较内容;StringBuilder可变是设计定位不同,不破坏String不可变性。

直接抓住三个锚点:引用和对象、字面量和 new、== 和 .equals()。这三点理清了,String 不可变性就稳了,不用背大段定义。
盯住“对象没变,只是引用换了”
面试最常设陷阱的代码就是:
String s = "hello";
s += " world";
这不是在改原对象,而是创建新对象,s 指向了新地址。原 "hello" 还在常量池里,只要没人引用,等 GC 回收。
- 验证方法:拼接前后用 == 比较,结果一定是 false
- 记住口诀:“字符串没有修改操作,只有生成操作”
- 所有方法如 replace、substring、trim、concat 都返回新 String,原对象纹丝不动
分清“哪里创建的,存在哪”
常量池不是万能收纳盒,它只对编译期确定的字符串字面量自动生效:
- String a = "abc"; String b = "abc"; → a == b 是 true(共用池中同一对象)
- String c = new String("abc"); → 一定在堆上新建对象,跟池无关
- c.intern() == a 是 true(强制入池,返回池中引用)
别再说“new String 创建两个对象”——准确说法是:如果池里还没 "abc",类加载时会先建一个池对象;运行时 new 再建一个堆对象,最多两个;已有则只建一个堆对象。
死磕 == 和 .equals() 的分工
这是检验是否真懂不可变性的试金石:
立即学习“Java免费学习笔记(深入)”;
- == 比的是内存地址:判断是不是同一个对象(比如单例校验、缓存命中)
- .equals() 比的是内容:String 重写后逐字符比较,因为业务关心“值一样”,不是“是不是同一个对象”
- 顺带记:hashCode() 也基于内容计算,并被缓存,所以 String 能安全当 HashMap 键——这正是不可变性换来的关键能力
别被 StringBuilder 带偏方向
看到 StringBuilder.append() 能“改内容”,不等于 String 可变。这是设计定位不同:
- StringBuilder 是专为拼接设计的可变工具,内部 char[] 或 byte[] 不加 final,也没封装保护
- String 的不可变是主动选择:用拼接性能换线程安全、常量池复用、哈希缓存、参数防篡改
- 面试被问“怎么高效拼接”,答“单线程用 StringBuilder,多线程用 StringBuffer”,别扯“让 String 可变”


















