在 Java 開發與面試中,String、StringBuffer 與 StringBuilder 是繞不開的經典話題。三者雖同為字串處理類別,但在可變性、執行緒安全與效能表現上卻有本質區別。掌握這些差異,不僅能寫出更高效的程式碼,更能在技術面試中遊刃有餘。
String:不可變的字串常量
String 內部使用 final char[] value 儲存字元。final 修飾符意味著陣列參考不可變,且 String 類別本身也被 final 修飾,無法被繼承。每次看似「修改」字串的操作(如拼接、替換),實際上都會在堆記憶體中建立全新的 String 物件,原物件若無引用則等待 GC 回收。
// 看似修改,實則新建物件
String s = "Hello";
s += " World"; // 產生新物件 "Hello World",原 "Hello" 失去引用
StringBuffer & StringBuilder:可變的字串建構器
兩者皆繼承自 AbstractStringBuilder,內部維護 char[] value 陣列(無 final 修飾)。擴容、新增、插入、刪除等操作直接在原陣列或擴容後的新陣列上進行,避免頻繁建立物件,大幅提升效能。
| 類別 | 執行緒安全 | 實現機制 | 適用場景 |
|---|---|---|---|
| String | ✅ 安全 | 不可變物件天生安全 | 常量、少量拼接、多執行緒共享 |
| StringBuffer | ✅ 安全 | 關鍵方法加 synchronized | 多執行緒環境下頻繁修改字串 |
| StringBuilder | ❌ 不安全 | 無同步鎖,單執行緒最高效 | 單執行緒、大量字串操作、效能敏感場景 |
StringBuffer 的核心方法(如 append()、insert()、reverse())均標註 synchronized,確保同一時間僅一個執行緒能操作內部陣列。但這也帶來鎖開銷。StringBuilder (JDK 1.5+) 移除同步鎖,在單執行緒下效能顯著優於 StringBuffer。
AbstractStringBuilder 定義了 expandCapacity()、append()、insert()、indexOf() 等核心邏輯。StringBuilder 與 StringBuffer 均透過 super.append(...) 復用父類實現,差別在於 StringBuffer 在公開方法上加 synchronized。
// 單執行緒大量拼接:StringBuilder 最快
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 100000; i++) sb.append(i);
// 多執行緒共享緩衝區:必須用 StringBuffer
StringBuffer sbf = new StringBuffer();
// 執行緒 A: sbf.append("A");
// 執行緒 B: sbf.append("B");
// 少量、固定字串:直接用 String 或 "+" (編譯器優化為 StringBuilder)
String msg = "User: " + name + ", ID: " + id;
StringBuilder(首選)StringBufferStringString s = "a" + "b" 會建立中間物件:編譯期常量折疊會直接優化為 "ab"。StringBuilder 絕對比 StringBuffer 快:單執行緒確實快,但多執行緒下若手動加鎖,反而比內建同步的 StringBuffer 更易出錯且效能無優勢。new StringBuilder(1024) 可減少擴容開銷。總結:理解底層 char[] 機制、final 語義與 synchronized 代價,才能在實戰中做出最優選擇。下次面試或 Code Review 時,不妨從「為何 String 設計為不可變?」切入,展現深度思考。