首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 程式設計入門

Java String 全面解析:對象特性、常量池機制、intern()原理與不可變性深度剖析

     編輯:Java 程式設計入門

String 基礎特性

  • 非基本類型,屬於引用類型,默認值 null
  • new String()、new String("") 創建空串(length()==0),非 null
  • final 類,不可繼承

字面量 vs new String:常量池機制

編譯期常量池

.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() 強制在堆創建新對象。

intern() 方法:手動入池


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

關鍵行為:

  1. 常量池無該字符串 → 添加並返回引用
  2. 常量池已存在 → 直接返回現有引用
  3. 不會 將堆對象地址「註冊」到常量池,原堆對象依然存在

equals() vs ==

  • ==:比較引用地址(是否同一對象)
  • equals():比較字符序列(Unicode 碼點)是否相同
  • 常量池機制下,字面量 == 可用;運行時創建對象必須用 equals()

不可變性設計與性能影響


String str = "kv" + "ill" + " " + "ans";
// 等價於:
// String tmp1 = "kvill";
// String tmp2 = "kvill ";
// String tmp3 = "kvill ans";
// str = tmp3;
// 產生 3 個臨時字符串對象

原因:value[] 數組 final,長度固定,任何拼接、修改都需創建新數組、新對象。

StringBuilder/StringBuffer 替代方案

類線程安全適用場景JDK 版本
StringBuffer同步方法,安全多線程環境1.0+
StringBuilder非同步,高性能單線程/局部變量5.0+

// 高效拼接
StringBuilder sb = new StringBuilder(64); // 預估容量避免擴容
sb.append("kv").append("ill").append(" ").append("ans");
String result = sb.toString();

最佳實踐總結

  1. 字符串常量優先使用字面量,利用常量池複用
  2. 頻繁拼接/修改使用 StringBuilder(單線程)或 StringBuffer(多線程共享)
  3. 需比較內容時堅持 equals(),除非確定為常量池引用
  4. 大量重複字符串可考慮 intern() 節省內存,但需權衡常量池擴容開銷(JDK 8+ 常量池在堆中,GC 可回收)
  5. 避免在循環中使用 + 拼接,編譯器雖優化為 StringBuilder,但每次循環仍創建新實例
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved