經典面試題:String s = "abc"; String s1 = "a"+"b"+"c"; 創建了幾個對象?答案取決於**編譯期常量折疊**與**運行時字符串常量池**機制。
String s = "abc";
String s1 = "a" + "b" + "c"; // 編譯期常量折疊 → "abc"
String 實例 "abc" 在常量池)。"a"+"b"+"c" 全為編譯期常量,`javac` 編譯時直接優化為 "abc" 字節碼(查看 javap -c 可見 ldc "abc")。運行時僅從常量池加載同一引用,s == s1 為 true。
String a = "abc";
String c = a + "d"; // 運行時 new StringBuilder().append(a).append("d").toString()
String d = a + "d"; // 另一次新建
a 常量池 "abc"、c 堆上新 String、d 堆上另一新 String)。a 的拼接無法編譯期確定,運行時通過 StringBuilder 生成新 String 對象(Java 9+ 可能用 invokedynamic 優化,但語義仍為新建)。c == d 為 false (不同堆對象),c.equals(d) 為 true (內容相同)。| 表達式 | 對象創建位置 | 備註 |
|---|---|---|
"literal" | 字符串常量池 (元空間) | 類加載時創建/復用 |
"a"+"b" (全常量) | 常量池 (編譯期折疊) | 等價於 "ab" |
new String("abc") | 堆內存 | 強制新建,**極少必要** |
var + "str" | 堆內存 | 運行時 StringBuilder 生成 |
str.intern() | 常量池 (可能新增) | 手動入池,慎用 |
"...",避免 new String()。StringBuilder 顯式控制,避免隱式創建大量臨時對象。equals()**,除非確定雙方均為常量池引用(如枚舉、常量定義)。