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

深度解析 Java String:常量池、intern()、不可變性與常見誤區

     編輯:Java 相關知識

1. String 不是基本類型

String 是對象,默認值 null。但它是特殊對象,擁有其他對象沒有的特性(如字面量語法、常量池、不可變性)。

2. 空字串 ≠ null

new String()     // 空串 ""
new String("")   // 空串 ""
String s = null  // null 引用

3. 字面量 vs new String():常量池機制

常量池:編譯期確定、存於 .class 文件,包含類、方法、接口常量及字符串常量。JVM 保證字符串常量在常量池中只有一份拷貝。

例 1:全是字面量

String s0 = "kvill";
String s1 = "kvill";
String s2 = "kv" + "ill";  // 編譯期常量折疊
s0 == s1  // true
s0 == s2  // true

三者皆指向常量池同一個 "kvill"。

例 2:涉及 new String()

String s0 = "kvill";
String s1 = new String("kvill");
String s2 = "kv" + new String("ill");
s0 == s1  // false
s0 == s2  // false
s1 == s2  // false

new String() 在運行期於堆上創建新對象,不進入常量池,各自擁有獨立地址。

4. String.intern():手動入池

intern() 將運行期字符串放入常量池:

  • 池中已有相同 Unicode 字符串 → 返回池中引用
  • 池中無 → 在池中創建並返回其引用

例 3:驗證行為

String s0 = "kvill";
String s1 = new String("kvill");
String s2 = new String("kvill");

s0 == s1                    // false
s1.intern();                // 返回池中引用,但未賦值給 s1
s0 == s1                    // false
s0 == s1.intern()           // true
s2 = s2.intern();           // 將池中引用賦給 s2
s0 == s2                    // true

例 4:破除「註冊自身地址」誤區

String s1 = new String("kvill");  // 類中無 "kvill" 字面量
String s2 = s1.intern();          // 池中新增 "kvill",s1 仍指向堆對象
s1 == s1.intern()   // false,證明原堆對象未被替換
s2 == s1.intern()   // true,s2 指向池中引用

結論:intern() 是在池中創建/查找,而非「註冊自身地址」。

5. equals() vs ==

  • equals():比較 Unicode 字符序列是否相等
  • ==:比較引用地址是否相同(是否同一對象)

6. 不可變性帶來的性能陷阱

String str = "kv" + "ill" + " " + "ans";

編譯期常量折疊優化為單一常量,但若涉及變量:

String a = "kv";
String b = "ill";
String str = a + b;  // 運行期創建 StringBuilder -> toString(),產生臨時對象

頻繁拼接建議用 StringBuffer(線程安全)或 StringBuilder(非線程安全、性能更優),它們是可變字符序列。

總結速查表

場景存儲位置== 比較結果
字面量 / 常量折疊常量池true(同一引用)
new String()堆false(不同對象)
intern() 後常量池與池中引用相同
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved