在Java中,String对象是不可变的 — 一旦创建,其内容永远无法改变。任何看起来修改String的操作实际上都会创建一个新的String。为了高效地重复修改,你使用StringBuilder。
String是不可变的
java
;
s.concat();
System.out.println(s);
s = s + ;
concat、toUpperCase、replace和substring等方法都返回新的String对象 — 原始String永远不会被修改。
✓ Thread safety — immutable objects are safe to share across threads (no locking)
✓ String pool — identical string literals can be SHARED/reused (memory savings)
✓ Hashing/keys — safe as HashMap keys (hashCode can be cached, never changes)
✓ Security — strings used for filenames, URLs, credentials can't be altered
after a security check
不可变性使String本质上是线程安全的,允许JVM通过字符串池内化(共享)字面量,并使它们作为map键时是可靠的(其哈希值永远不会改变)。
// ❌ creates a NEW string object on EVERY iteration — O(n²), wasteful
String result = "";
for (int i = 0; i < 10000; i++) {
result += i; // each += allocates a whole new string
}
因为每个+=都会创建一个新String(复制所有之前的内容),在循环中构建字符串是二次方的,会产生大量垃圾。
// ✅ StringBuilder mutates an internal buffer — O(n), efficient
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10000; i++) {
sb.append(i); // modifies the buffer in place, no new objects
}
String result = sb.toString(); // convert to a String once, at the end
StringBuilder是一个可变的字符序列 — append/insert/delete修改其内部缓冲区而不创建新对象,使基于循环的构建变得高效。(StringBuffer是线程安全但速度较慢的变体。)
String不可变性是Java的一个定义性特征,具有重要的后果:它提供线程安全,启用节省内存的字符串池,并使String在map键和安全上下文中是安全的 — 但这也意味着在循环中进行天真的字符串连接是真正的性能陷阱(O(n²),产生过多垃圾)。
知道在重复修改时使用StringBuilder是一种实际需要,直接来自对不可变性的理解。
这个结合 — 为什么String是不可变的(安全、共享、哈希)和何时切换到StringBuilder(循环连接)— 既是常见的面试话题,也是频繁的现实世界性能优化。