Java 字串物件建立有兩種方式:字面值(String s = "abc")與 new String()。JVM 為減少重複物件創建,維護一塊特殊記憶體區域——字串常量池(String Constant Pool),儲存字串物件的引用而非物件本身(物件實體在堆中)。
String s1 = "droid"; // 建立物件,引用入池 String s2 = "droid"; // 直接返回池中引用 System.out.println(s1 == s2); // true
無論常量池是否有相同內容,new String("droid") 都會在堆中建立新物件,不進入常量池:
String s3 = new String("droid");
System.out.println(s1 == s3); // false
呼叫 intern() 可將堆中字串物件引用加入常量池:
String s4 = s3.intern(); // 檢查池中有無 "droid",有則返回池中引用,無則將 s3 引用入池並返回 System.out.println(s4 == s1); // true
儲存的是引用。驗證:嘗試將 82MB 影片檔讀為字串並 intern(),設 -XX:PermSize=6m(Java 8 前常量池在永久代)不會 OOM,證明 char[] 實體不在常量池。
唯有 String 為 final 不可變,多執行緒共享同一物件才安全。若可變,一處修改會影響所有引用者。
String test = "a" + "b" + "c";
編譯期直接合併為 "abc",僅建立一個物件、一個池引用。javap -c 反編譯可見 ldc #2 // String abc。
new String()intern() 手動入池intern(),防止常量池膨脹影響效能