首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計疑難解答

Java 字符串內部機制深度解析:編譯期優化、常量池與 new String() 的區別

     編輯:程式設計疑難解答

問題代碼與輸出

String a = fuse("a", "");
String b = fuse("a", "");
System.out.println(a == b); // false

String c = "a" + "";
String d = "a" + "";
System.out.println(c == d); // true

String e = fuse("a");
String f = fuse("a");
System.out.println(e == f); // true

三個結果的深度解析

1. c 和 d:編譯期常量折疊

String c = "a" + "";
String d = "a" + "";
// 編譯器優化:視為常量表達式
// 編譯時直接計算為 "a"
// 存入字符串常量池
// c 和 d 指向同一個常量池對象
// c == d → true

2. e 和 f:方法返回值優化 + 常量池

static String fuse(String t1) { return t1; }

String e = fuse("a");
String f = fuse("a");
// 參數 "a" 是字面量,已在常量池
// 方法直接返回參數引用,無新建對象
// e 和 f 都指向常量池中同一個 "a"
// e == f → true

3. a 和 b:運行時拼接創建新對象

static String fuse(String t1, String t2) { return t1 + t2; }

String a = fuse("a", "");
String b = fuse("a", "");
// t1 + t2 在運行時執行
// 底層使用 StringBuilder 拼接
// new StringBuilder().append(t1).append(t2).toString()
// toString() 會 new String(char[]) 創建堆上新對象
// 每次調用都創建新對象,地址不同
// a == b → false

字符串對象創建對比表

表達式創建對象數存儲位置備註
"abc"0 或 1常量池常量池去重
new String("abc")1 或 2堆堆上新對象,"abc" 可能在常量池
"a" + "b"0 或 1常量池編譯期優化為 "ab"
s1 + s2 (變量)1堆運行時 StringBuilder.toString()
s.intern()0 或 1常量池手動入池,返回池中引用

JDK 版本差異注意

  • JDK 7 前:常量池在永久代 (PermGen)
  • JDK 7+:常量池移至堆中
  • JDK 9+:字符串底層改用 byte[] + coder (Compact Strings)

最佳實踐

  1. 比較內容用 equals():"abc".equals(str)
  2. 拼接用 StringBuilder:循環中避免隱式創建大量臨時對象
  3. 常量池利用:String s = "a" + "b"; 優于 String s = "a"; s += "b";
  4. intern() 謹慎使用:大量調用可能導致常量池膨脹 (JDK 7+ 在堆中相對安全)

總結

三個結果的本質區別在於:編譯期常量折疊 vs 運行時拼接新建對象。字符串常量池是 JVM 優化字符串存儲的關鍵機制,理解其工作原理能寫出更高性能的代碼。

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