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

為什麼 Java String 物件是不可變的?深度剖析與反射破解

     編輯:Java 相關知識

不可變物件定義與 String 設計哲學

不可變物件:建立後狀態永不改變。Java String 設計為不可變,帶來多重效益:

  • 字串常量池共享:相同字面值複用同一物件,節省記憶體
  • 執行緒安全:無狀態變更,天然免疫競態條件
  • 安全性:網路連線、檔案路徑、類別載入等敏感參數防篡改
  • HashCode 快取:hashCode() 計算一次後快取,提升 HashMap/HashSet 效能

JDK 內部結構演進

版本核心欄位備註
JDK 6/7char[] value, int offset, int count, int hash支援 substring 共享底層陣列(記憶體洩漏風險)
JDK 7u6+char[] value, int hashsubstring 複製新陣列,修復記憶體洩漏
JDK 9+byte[] value, byte coder (LATIN1/UTF16), int hashCompact Strings,節省 50% 記憶體

常見誤區:參考變更 vs 物件變更


String s = "ABC";
s = "123";  // 參考 s 指向新物件,原 "ABC" 物件未變

所有「修改」方法(replace、substring、toLowerCase 等)實際上都是建立新 String 物件回傳,原物件保持不變。

原始碼級驗證:replace 方法實作


public String replace(char oldChar, char newChar) {
    if (oldChar != newChar) {
        int len = value.length;
        int i = -1;
        char[] val = value; // 欄位為 final,不可重新指派
        while (++i < len) {
            if (val[i] == oldChar) break;
        }
        if (i < len) {
            char[] buf = new char[len];
            for (int j = 0; j < i; j++) buf[j] = val[j];
            while (i < len) {
                char c = val[i];
                buf[i] = (c == oldChar) ? newChar : c;
                i++;
            }
            return new String(buf, true); // 建立新物件
        }
    }
    return this; // 無變化回傳自身
}

反射破解不可變性(僅供教學,生產環境嚴禁)


public static void hackString() throws Exception {
    String s = "Hello World";
    System.out.println("修改前: " + s); // Hello World

    Field valueField = String.class.getDeclaredField("value");
    valueField.setAccessible(true);
    char[] value = (char[]) valueField.get(s);
    value[5] = '_'; // 直接修改底層陣列

    System.out.println("修改後: " + s); // Hello_World
}

警告:此行為違反 String 契約,會導致字串常量池污染、HashMap 鍵值查找失效、安全檢查繞過等嚴重後果。

最佳實踐建議

  1. 頻繁字串拼接使用 StringBuilder(非執行緒安全)或 StringBuffer(執行緒安全)
  2. 避免在循環中使用 + 拼接長字串
  3. 利用 String.join()、String.format()、Collectors.joining() 簡化代碼
  4. JDK 11+ 可用 String.repeat()、String.strip() 等新方法
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved