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

通過反編譯深度解析 String.intern() 與字符串常量池機制

     編輯:Java 綜合教學

通過反編譯深度解析 String.intern() 與字符串常量池機制

一、 核心結論速覽

場景JDK 1.6JDK 1.7+
String s = new String("abc") 創建對象數2(常量池 "abc" + 堆對象)2
字面量 "abc" 多次出現指向常量池同一引用同
new String("abc").intern()常量池無則複製引用入池,有則返回池中引用常量池無則在池中記錄堆對象引用(不複製),有則返回池中引用
final 變量參與 + 拼接編譯期常量折疊為單一字面量同
非常量變量 + 拼接運行期 StringBuilder 生成新對象同

二、 經典面試題反編譯還原

案例 1:new String("string") vs intern()

String str1 = "string";
String str2 = new String("string");
String str3 = str2.intern();
System.out.println(str1 == str2); // false:str1指常量池,str2指堆
System.out.println(str1 == str3); // true:intern()返回常量池引用

案例 2:編譯期常量折疊與 final 語義

final String baseFinal = "baseStr";
String str1 = "baseStr01";
String str2 = "baseStr" + "01";        // 編譯期合併 → "baseStr01"
String str3 = baseStr + "01";          // 運行期 StringBuilder
String str4 = baseFinal + "01";        // 編譯期常量折疊 → "baseStr01"
String str5 = new String("baseStr01").intern();

System.out.println(str1 == str2); // true
System.out.println(str1 == str3); // false
System.out.println(str1 == str4); // true
System.out.println(str1 == str5); // true

反編譯關鍵字節碼:

  • str2:ldc #常量池索引 直接加載合併後字面量。
  • str3:new StringBuilder → dup → invokespecial → aload → invokevirtual append → ldc "01" → invokevirtual append → invokevirtual toString。
  • str4:ldc #常量池索引(final 導致編譯期替換)。
  • str5:new String → dup → ldc "baseStr01" → invokespecial → invokevirtual intern。

案例 3:intern() 執行順序對 JDK 1.6/1.7 行為差異的影響

// 版本 A
String str2 = new String("str") + new String("01");
str2.intern();          // 先 intern
String str1 = "str01";  // 後字面量
System.out.println(str2 == str1); // JDK6: true, JDK7+: false

// 版本 B
String str1 = "str01";  // 先字面量
String str2 = new String("str") + new String("01");
str2.intern();          // 後 intern
System.out.println(str2 == str1); // JDK6: false, JDK7+: false

原理:

  • JDK 6:常量池在永久代,intern() 會將字符串複製到常量池。版本 A 先 intern() 將堆對象引用複製入池,後字面量直接複用池中引用 → true。
  • JDK 7+:常量池移至堆,intern() 僅在常量池記錄堆對象引用(不複製)。版本 A 先 intern() 記錄堆引用,後字面量在常量池創建新引用指向新字符串對象 → 兩引用指向不同對象 → false。

三、 高頻面試題速答

  1. String s = new String("xyz") → 2 個對象(常量池 "xyz" + 堆對象)。
  2. String s1="abc", s2="abc" → true(同常量池引用)。
  3. new String("abc") 兩次 → false(兩個堆對象)。
  4. s2+s3 非 final 變量拼接 → false(StringBuilder 生成新對象)。
  5. final String s2="a", s3="bc"; s2+s3 → true(編譯期折疊為 "abc")。

掌握 String、常量池、intern()、final 編譯期優化、JDK 版本差異,是攻克字符串面試題與避免生產 Bug 的利器。

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