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

深度解析 Java String 與 intern() 機制:從反編譯視角探討字串常量池

     編輯:Java 程式設計入門

前言:為何字串面試題屢見不鮮?

字串在日常開發中極為常見,用法看似簡單,卻蘊含深層機制。面試官偏愛考察 String 相關題目,不僅測試 Java 基礎掌握程度,更考驗候選人對技術細節的探究態度。本文將通過反編譯字節碼,結合 JVM 內存模型演進,徹底剖析 String 與 intern() 的核心邏輯,助你攻克經典面試難題。

核心概念:字面量賦值 vs new 關鍵字

字串創建機制示意圖

字面量賦值:優先檢查字串常量池,若存在則直接引用;否則在常量池創建並引用。

new 關鍵字:直接在堆內存創建新對象,引用指向堆地址。JDK 7 起 HotSpot 將常量池從永久代移至堆中(詳見《JDK8 內存模型——消失的 PermGen》)。

intern() 方法可將堆中字串對象加入常量池,返回常量池引用。

代碼段一:基礎對比

String str1 = "string";
String str2 = new String("string");
String str3 = str2.intern();
System.out.println(str1 == str2); // #1
System.out.println(str1 == str3); // #2

結果分析:

  • #1 輸出 false:str1 指向常量池,str2 指向堆對象,地址不同。
  • #2 輸出 true:str2.intern() 將 "string" 置入常量池,但常量池已存在該字串(str1 引用),故直接返回常量池引用,str3 指向 str1 同一地址。

代碼段一運行結果

代碼段二:編譯期優化與 final 語義

通過 javap -c -verbose StringTest01.class 反編譯觀察字節碼指令:

常量池內容

執行指令

關鍵指令解讀:

  • ldc:從運行時常量池加載引用至棧。
  • astore_n:將引用存入第 n 個局部變量。

執行流程關鍵點:

  1. str1、str2 均為字面量 "baseStr01",編譯期合併為常量池同一項 → #3 輸出 true。
  2. str3 = baseStr + "01":非 final 變量,運行期通過 StringBuilder.append() 拼接,生成新堆對象 → #4 輸出 false。
  3. str4 = baseFinalStr + "01":final 變量編譯期常量折疊,直接引用常量池 "baseStr01" → #5 輸出 true。
  4. str5 = new String("baseStr01").intern():堆對象調用 intern(),常量池已存在 "baseStr01",返回常量池引用 → #6 輸出 true。

代碼段二運行結果

代碼段三:JDK 1.6 vs 1.7+ intern() 行為差異

// 情況 1:先 intern 再字面量賦值
String str2 = new String("str") + new String("01");
str2.intern();
String str1 = "str01";
System.out.println(str2 == str1); // #7

// 情況 2:先字面量賦值再 intern
String str1 = "str01";
String str2 = new String("str") + new String("01");
str2.intern();
System.out.println(str2 == str1); // #8

JDK 1.6 運行結果

JDK 1.7+ 運行結果

核心差異:JDK 1.7 起常量池移至堆,intern() 不再複製字串,而是在常量池記錄堆對象引用。

  • #7 (JDK 1.7+ true):先執行 intern(),常量池無 "str01",記錄堆對象引用;後執行字面量賦值,常量池已有引用,直接返回 → 兩者指向同一堆對象。
  • #8 (JDK 1.7+ false):先字面量賦值,常量池創建 "str01";後 intern() 發現常量池已存在,不改變引用 → str1 指向常量池對象,str2 指向堆對象。

高頻面試題速查

new String("abc").intern() == "abc"
題目答案核心原理
String s = new String("xyz") 創建幾個對象?兩個常量池 "xyz" + 堆中新對象
String s1="abc"; String s2="abc"; s1==s2true均指向常量池同一對象
String s1=new String("abc"); String s2=new String("abc"); s1==s2false兩個獨立堆對象
非 final 變量拼接 vs final 變量拼接false / true編譯期常量折疊 vs 運行期 StringBuilder
true (JDK 1.7+)intern 返回常量池引用

總結

掌握 String 常量池、堆內存交互、intern() 語義演進、編譯期優化(final 常量折疊、字面量合併)及字節碼指令(ldc、invokespecial、invokevirtual),即可洞悉所有字串面試題本質。建議結合 javap 實際反編譯驗證,深化理解。

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