String 不可變是 Java 基礎中最高頻考點之一。本文通過三張內存圖解,直觀展示字符串賦值、引用傳遞、拼接操作的內存變化,並給出 StringBuilder 高效拼接最佳實踐。
String s = "abcd";

s 存儲引用,指向堆/常量池中的 "abcd" 對象。String s2 = s;
s2 複製引用值,雙雙指向同一 "abcd" 對象。s == s2 為 true。s = s.concat("ef");

concat 內部創建 新 String 對象 "abcdef"。s 更新引用指向新對象,原 "abcd" 仍在常量池(若無其他引用則等待 GC)。String 方法均不修改原對象,而是返回新對象。循環拼接字符串會產生大量中間對象,觸發頻繁 GC:
// 反例:O(n²) 創建對象
String result = "";
for (String part : parts) result += part;
正確姿勢:使用 StringBuilder(單線程)或 StringBuffer(線程安全):
public static String readFileToString() throws IOException {
File file = new File("src/TestRead.java");
StringBuilder sb = new StringBuilder(1000); // 預估容量避免擴容
try (BufferedReader br = new BufferedReader(new FileReader(file))) {
char[] buf = new char[1024];
int len;
while ((len = br.read(buf)) != -1) {
sb.append(buf, 0, len);
}
}
return sb.toString();
}
StringBuilder 內部維護可變 char[],擴容策略為 2倍+2,append 為 O(1) 均攤。new String() 強制堆分配。StringBuilder,避免 O(n²) 對象創建與 GC 壓力。