String a = "ab"; String b = "a" + "b"; 打印什麼?三類典型回答:
+ 產生新對象,== 比較引用。"a"+"b" 編譯期優化為 "ab",複用池中對象。第 3 類最接近真相,但理由略有偏差——根本不存在運行期 "a"+"b" 拼接操作。
// 版本 A
private String a = "aa";
// 版本 B
private String a = "a" + "a";
編譯後用十六進制編輯器對比 .class 文件,**完全逐字節一致**。證明編譯器在編譯期直接將 "a"+"a" 常量折疊為 "aa",運行期只見 ldc "aa" 指令。
| 表達式 | 結果 | 說明 |
|---|---|---|
"a" + "b" | true | 字面量拼接 ✅ |
"a" + 1 / "a" + true / "a" + 3.4 | true | 字面量 + 基本類型 ✅ |
"a" + bb (bb 為變量) | false | 變量阻礙編譯期求值 ❌ |
final String bb = "b"; "a" + bb | true | 編譯期常量傳播 ✅ |
final String bb = getBB(); "a" + bb | false | 方法調用非編譯期常量 ❌ |
Java 語言規範(JLS)將 String 視為「準基本類型」:
final 常量變量、基本類型運算組成,編譯器必須編譯期求值。+ 運算符重載:Java 唯一的運算符重載,專供 String 拼接,編譯器將其降級為 StringBuilder.append() 或直接常量折疊。String.intern() 可手動入池。StringBuilder**,避免產生大量中間對象觸發 GC。final 修飾引用類型僅保證引用不變,**不保證對象內容不變**,編譯器優化依賴「值不可變」的語義推導。Java 對 String 的優化可謂「到了極點」——從語法糖、常量池到 JIT 內聯,將一個普通對象打造成接近基本類型的高性能數據類型。