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

深度解析 Java String:字符串常量池、intern()、不可變性與性能陷阱

     編輯:Java 相關知識

String 不是基本類型

String 是 java.lang.Object 的子類,默認值 null。但它擁有特殊語法支持(字面量、+ 拼接)且被 JVM 深度優化。

字面量 vs new String():字符串常量池

編譯期確定的字符串字面量(如 "kvill")存入 .class 文件的常量池,類加載時進入 運行時常量池(方法區/元空間)。JVM 保證全局唯一:相同字面量只有一份拷貝。

String s0 = "kvill";
String s1 = "kvill";
String s2 = "kv" + "ill"; // 編譯期常量折疊為 "kvill"
System.out.println(s0 == s1); // true
System.out.println(s0 == s2); // true

new String("kvill") 在運行時於堆中創建新對象,不進入常量池,每次調用都分配新內存:

String s3 = new String("kvill");
System.out.println(s0 == s3); // false

intern():手動入池

String.intern() 是 native 方法,邏輯如下:

  1. 檢查運行時常量池是否已有內容相等(equals())的字符串;
  2. 有則返回該引用;
  3. 無則將當前對象的引用存入常量池並返回(JDK 7+ 不再複製對象,直接存引用)。
String s1 = new String("kvill");
String s2 = s1.intern(); // 常量池無 "kvill",存入 s1 引用
System.out.println(s1 == s2); // false!s1 仍指向堆對象
System.out.println(s1.intern() == s2); // true,intern() 返回常量池引用

誤區澄清:intern() 不會把堆對象「變成」常量池對象,只是讓常量池持有對堆對象的引用(或複製,視 JDK 版本)。原堆對象依然存在。

== vs equals()

  • == 比較引用地址(是否同一對象)。
  • equals() 比較字符序列(Unicode 碼點逐個比對)。
  • 日常判斷內容相等永遠用 equals();只有確定引用來自常量池或同一 intern() 結果時才用 == 優化。

不可變性帶來的性能陷阱

String 一旦創建不可修改。String s = "a" + "b" + "c"; 編譯器優化為 "abc";但 String s = ""; for (...) s += x; 循環中每次拼接都產生新 StringBuilder → toString(),產生大量臨時對象,拖垮 GC。

最佳實踐:

  • 已知拼接次數:直接用 +,編譯器自動優化為 StringBuilder。
  • 循環/動態拼接:顯式用 StringBuilder(單線程)或 StringBuffer(多線程)。
  • 大量字符串處理場景考慮 CharSequence、StringJoiner、TextBlock(Java 13+)。

總結

理解常量池、堆、intern() 三者關係,是寫出高性能、無 Bug 字符串代碼的關鍵。記住:內容比較用 equals,引用比較用 ==,拼接用 StringBuilder,池化用 intern()(謹慎使用,防止元空間 OOM)。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved