String设计为不可变,因其内部value数组被final修饰且私有,所有修改操作均返回新对象;这保障了线程安全、常量池复用、哈希缓存优化及关键参数安全性。

Java 字符串面试题核心就三点:理解 String 的不可变性、掌握字符串常量池机制、分清 == 和 equals() 的本质区别。答得准,关键在讲清楚“为什么”,而不是只背结论。
String 为什么设计成不可变?
不可变(immutable)不是语法限制,而是通过源码实现的——String 内部用 final char[](Java 8 及之前)或 final byte[](Java 9+)存储内容,且所有修改方法(如 substring、toUpperCase)都返回新对象,不改变原实例。
- 安全性:作为类加载器、URL、文件路径等关键参数,不可变可防止被意外或恶意篡改
- 线程安全:天然无状态,无需同步,多线程下直接共享无风险
- 哈希缓存优化:
hashCode在首次调用时计算并缓存,后续复用,提升HashMap等集合性能 - 字符串常量池复用基础:只有确定不会变,JVM 才敢放心地把相同字面量指向同一个对象
字符串常量池到底存在哪?怎么触发入池?
Java 7 起,字符串常量池从永久代(PermGen)移到堆内存(Heap),位置变了,但逻辑没变。入池时机分两种:
-
编译期确定的字面量:如
String s = "abc";,JVM 加载类时自动放入常量池 -
运行期手动入池:调用
String.intern(),若池中已有相同内容字符串,返回池中引用;否则将当前字符串对象加入池并返回其引用
注意:new String("abc") 会创建两个对象——堆上一个新对象 + 常量池里已有的字面量(如果存在),两者地址不同。
立即学习“Java免费学习笔记(深入)”;
== 和 equals 到底比什么?什么时候结果不同?
== 比的是引用是否指向同一内存地址;equals() 在 String 中重写为比较字符内容是否完全一致(逐个字符比,长度和每个 char 都相等)。
-
"abc" == "abc"→ true(字面量,共用常量池中同一对象) -
new String("abc") == new String("abc")→ false(两个堆对象,地址不同) -
new String("abc").equals(new String("abc"))→ true(内容相同) -
new String("abc").intern() == "abc"→ true(intern()后指向常量池对象)
StringBuilder 和 StringBuffer 该怎么选?
两者都可变、都用于高效拼接,区别只在并发场景:
-
StringBuffer方法全加了synchronized,线程安全但有性能开销 -
StringBuilder无同步,单线程下更快,是日常拼接首选 - 除非明确多线程共享并修改同一个字符串缓冲区,否则不用
StringBuffer
小技巧:循环内拼接字符串,别用 +=(底层每次新建 StringBuilder),显式用 StringBuilder.append() 更清晰高效。


















