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

Java String.intern() 方法深度解析:JDK 6 vs JDK 7+ 差異

     編輯:Java 相關知識

字串常量池演進

版本常量池位置intern() 行為
JDK 6永久代不存在則複製字串到常量池
JDK 7+堆內存不存在則存入引用指向堆中字串

核心差異示意

String s = new String("abc");  // 堆中建立 "abc" 物件
s.intern();

// JDK 6: 永久代常量池新建 "abc" 副本,返回副本引用
// JDK 7+: 堆常量池存入 s 的引用,返回 s 引用

經典驗證案例

public class InternTest {
    public static void main(String[] args) {
        // 案例 1:運算式產生的字串
        String str = "str" + new String("01");  // 堆中新物件 "str01"
        str.intern();                           // 註冊到常量池
        String str1 = "str01";                  // 常量池直接取得
        System.out.println(str == str1);        // JDK6: false | JDK7+: true
        
        // 案例 2:new String() 後再 intern
        String str2 = new String("str01");      // 堆中新物件
        str2.intern();                          // 常量池已有 "str01"(來自 str1)
        String str3 = "str01";
        System.out.println(str2 == str3);       // false(str2 指向堆舊物件)
        
        // 案例 3:純字面量組合
        String str4 = "str01";
        String str5 = new String("str") + new String("01"); // 堆新物件
        str5.intern();
        System.out.println(str4 == str5);       // false
    }
}

執行結果對照

案例JDK 6JDK 7/8/11/17+關鍵原因
案例 1falsetrueJDK7+ intern 存引用,str 和 str1 指向同一堆物件
案例 2falsefalsestr2 建立時常量池已有引用,intern 不改變 str2 指向
案例 3falsefalsestr5 指向堆新物件,intern 只登記引用不改變 str5 指向

記憶體模型圖解

JDK 6

堆內存:     [String "str01"@0x100] ← str
永久代常量池: ["str01"@0x200] ← str1, intern() 複製體

JDK 7+

堆內存:     [String "str01"@0x100] ← str, str1, intern() 登記引用
堆常量池:   [ref@0x100] ← 指向同一物件

實務指導原則

  1. 不要依賴 intern() 進行字串比較:永遠用 equals()
  2. 大量重複字串可考慮 intern:如解析 XML/JSON 產生大量相同標籤名,可減少記憶體佔用
  3. JDK 7+ 常量池在堆中:受 -Xmx 限制,大量 intern 可能導致 OOM,需監控
  4. 字面量自動入池:"abc" 編譯期進入常量池,new String("abc") 執行期在堆建立
  5. 編譯期優化:"a" + "b" → "ab"(常量折疊),"a" + new String("b") → 堆中新物件

常見誤區

誤區真相
intern() 會修改原字串引用String 不可變,intern() 只返回常量池引用,不改變呼叫者引用
所有字串都在常量池只有字面量和調用 intern() 的字串(引用)在常量池
JDK 7+ intern() 會複製字串只存引用,不複製字元陣列

總結

String.intern() 是手動將字串引用登記到全局常量池的機制。JDK 7 將常量池從永久代移至堆,並改為存儲引用而非複製,導致運算式產生的字串經 intern() 後可與字面量共享同一物件。理解這一演進,有助於排查字串比較異常、優化大量重複字串記憶體佔用,但日常開發堅持使用 equals() 比較內容。

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