nullnew String()、new String("") 創建空串(length()==0),非 nullfinal 類,不可繼承.class 文件中存儲字面量符號引用。JVM 類加載時將其載入運行時常量池(方法區/元空間)。
// 案例 1:純字面量
String s0 = "kvill";
String s1 = "kvill";
String s2 = "kv" + "ill"; // 編譯期常量折疊
System.out.println(s0 == s1); // true
System.out.println(s0 == s2); // true
// 案例 2:包含 new String
String s0 = "kvill";
String s1 = new String("kvill");
String s2 = "kv" + new String("ill");
System.out.println(s0 == s1); // false
System.out.println(s0 == s2); // false
System.out.println(s1 == s2); // false
結論:字面量及編譯期可確定的常量表達式指向常量池同一實例;new String() 強制在堆創建新對象。
String s0 = "kvill";
String s1 = new String("kvill");
String s2 = new String("kvill");
System.out.println(s0 == s1); // false
s1.intern(); // 返回常量池引用,但未賦值給 s1
System.out.println(s0 == s1); // false
System.out.println(s0 == s1.intern()); // true
s2 = s2.intern(); // 賦值:s2 指向常量池實例
System.out.println(s0 == s2); // true
關鍵行為:
==:比較引用地址(是否同一對象)equals():比較字符序列(Unicode 碼點)是否相同== 可用;運行時創建對象必須用 equals()
String str = "kv" + "ill" + " " + "ans";
// 等價於:
// String tmp1 = "kvill";
// String tmp2 = "kvill ";
// String tmp3 = "kvill ans";
// str = tmp3;
// 產生 3 個臨時字符串對象
原因:value[] 數組 final,長度固定,任何拼接、修改都需創建新數組、新對象。
| 類 | 線程安全 | 適用場景 | JDK 版本 |
|---|---|---|---|
| StringBuffer | 同步方法,安全 | 多線程環境 | 1.0+ |
| StringBuilder | 非同步,高性能 | 單線程/局部變量 | 5.0+ |
// 高效拼接
StringBuilder sb = new StringBuilder(64); // 預估容量避免擴容
sb.append("kv").append("ill").append(" ").append("ans");
String result = sb.toString();
StringBuilder(單線程)或 StringBuffer(多線程共享)equals(),除非確定為常量池引用intern() 節省內存,但需權衡常量池擴容開銷(JDK 8+ 常量池在堆中,GC 可回收)+ 拼接,編譯器雖優化為 StringBuilder,但每次循環仍創建新實例