String不可变指所有修改操作均创建新对象,原对象内容恒定;源于final类、私有final数组及无修改方法的设计,保障常量池复用、线程安全与hashCode缓存。

面试中关于 String 不可变性的提问,从来不是考你背没背过“final char[]”——而是看你能不能在追问里不露破绽。掉坑的根源,往往不是不知道答案,而是没分清三组关键关系:引用和对象、字面量和 new、== 和 .equals()。
别把“s = s + 'a'”当成修改原对象
这是最常被误读的操作。代码写起来像在改内容,实际每次拼接都生成全新对象,原字符串毫发无损:
- s += "x" 等价于 s = new StringBuilder().append(s).append("x").toString()
- 原字符串仍驻留在内存中(等 GC 回收),s 只是换了个新地址指向
- 用 == 比较拼接前后的变量,结果一定是 false,能立刻验证是否理解到位
分清字面量和 new 创建的对象
常量池只对字符串字面量自动生效;new 出来的对象默认在堆上,哪怕内容一模一样也不共享:
- String a = "abc"; String b = "abc"; → a == b 为 true(共用常量池中同一对象)
- String c = new String("abc"); String d = new String("abc"); → c == d 为 false(两个独立堆对象)
- c.intern() == a 为 true(intern() 强制入池并返回池中引用)
== 和 .equals() 必须讲透本质区别
不能只说“==比地址,equals比内容”,要落到设计意图和使用场景:
立即学习“Java免费学习笔记(深入)”;
- == 是判断“是不是同一个对象”,适用于缓存命中检查、单例判等
- .equals() 是 String 重写后逐字符比内容,因为业务关心的是“值相等”
- 延伸点:String 的 hashCode() 基于内容计算且缓存,所以能安全作 HashMap 键——这正是不可变性带来的直接收益
别拿 StringBuilder 反推 String 可变
看到 StringBuilder.append() 能改内容,就认为“String 其实也能改,只是没提供方法”,这是典型逻辑倒置:
- StringBuilder 是专为可变场景设计的工具类,内部 char[] 没有 final,也没私有封装限制
- String 的不可变是主动设计选择,不是功能缺失;它用拼接性能换来了线程安全、常量池复用、哈希缓存、系统安全性
- 面试被问“怎么高效拼接”,答“用 StringBuilder”即可;若被问“为什么不用 String 拼接”,重点讲清楚中间对象爆炸和 GC 压力


















