| 特性 | String | StringBuffer | StringBuilder |
|---|---|---|---|
| 可變性 | 不可變 | 可變 | 可變 |
| 線程安全 | 天然安全 | 同步方法,安全 | 非同步,不安全 |
| 性能 | 拼接產生新對象 | 鎖開銷,單線程較慢 | 無鎖,單線程最快 |
| 適用場景 | 常量、鍵、少量拼接 | 多線程共享緩衝區 | 單線程大量拼接、構建器 |
| 繼承關系 | final class | extends AbstractStringBuilder | extends AbstractStringBuilder |
String s = "ab";
s = s + "cd"; // 實際:new StringBuilder().append("ab").append("cd").toString()
// 產生 3 個對象:"ab"、"cd"、新 StringBuilder、結果 String
// 原 "ab" 變垃圾,等待 GC
字符串常量池:字面量 "abc" 存放在常量池,new String("abc") 強制創建堆對象。intern() 可手動入池。
String a1 = new String("abc");
String a2 = new String("abc");
String a3 = "abc";
String a4 = "abc";
a1.equals(a2); // true - 內容比較
a1 == a2; // false - 引用比較,不同堆對象
a3 == a4; // true - 常量池同一引用
a1 == a3; // false - 堆 vs 常量池
==:比較引用地址(基本類型比值)equals():比較內容(Object 默認比引用,String 重寫比內容)public class ConcatBenchmark {
static final int N = 100_000;
public static void main(String[] args) {
// String +=
long t1 = System.nanoTime();
String s = "";
for (int i = 0; i < N; i++) s += "x";
long t2 = System.nanoTime();
// StringBuilder
long t3 = System.nanoTime();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < N; i++) sb.append('x');
String r = sb.toString();
long t4 = System.nanoTime();
System.out.printf("String += : %.2f ms%n", (t2-t1)/1e6);
System.out.printf("StringBuilder: %.2f ms%n", (t4-t3)/1e6);
// 典型輸出:String += 12000 ms, StringBuilder 2 ms
}
}
| 操作 | String | StringBuilder/Buffer |
|---|---|---|
| 長度 | length() | length() |
| 字符訪問 | charAt(i) | charAt(i) |
| 子串 | substring(begin, end) | substring(begin, end) |
| 查找 | indexOf(str), lastIndexOf, contains | indexOf(str) |
| 替換 | replace(old, new), replaceAll(regex, repl) | replace(start, end, str) |
| 分割 | split(regex) | — |
| 大小寫 | toUpperCase(), toLowerCase() | — |
| 去空白 | trim(), strip() (Java 11) | — |
| 格式化 | String.format(), String.join() | append() 鏈式 |
| 轉數組 | toCharArray(), getBytes() | toString() → 再轉 |
| 容量管理 | — | capacity(), ensureCapacity(), trimToSize() |
最佳實踐總結
- 單線程拼接循環:
StringBuilder(預估容量new StringBuilder(1024)避免擴容)- 多線程共享緩衝:
StringBuffer或ThreadLocal<StringBuilder>- 常量/鍵/少量拼接:直接用
String,編譯器優化常量折疊- 格式化:
String.format、MessageFormat、StringJoiner- 比較內容:永遠用
equals(),Objects.equals(a,b)防空指針- 避免在循環中 +=:O(n²) 災難,代碼審查必查項
理解 String 不可變設計與 StringBuilder 可變緩衝機制,是寫出高性能、低 GC 壓力 Java 代碼的基本功。