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

為什麼 Java 字符串是不可變的?三大核心原因深度解析

     編輯:Java 相關知識

不可變對象定義

創建後狀態不可修改的對象。String 是典型代表:

String s = "ABC";
s.toLowerCase(); // 返回新對象 "abc",原 "ABC" 不變

原因一:字符串常量池機制

字符串常量池示意

String s1 = "abcd";
String s2 = "abcd"; // 指向同一個池對象
String s3 = "ab" + "cd"; // 編譯期優化,同指向 "abcd"
  • 池依賴**不可變性**:多引用共享同一對象,任一引用修改會影響其他引用,破壞語義
  • 不可變使「引用共享」安全,實現 String.intern() 去重、節省記憶體
  • 編譯器常量折疊("ab"+"cd" → "abcd")也依賴不可變語義

原因二:HashCode 緩存優化

String 大量用作 HashMap/HashSet Key,頻繁計算 hashCode()。

public final class String {
    private int hash; // 默認 0,首次計算後緩存
    public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            hash = h = computeHashCode(); // 計算並緩存
        }
        return h;
    }
}
  • 不可變保證 hashCode **終身不變**,可安全緩存
  • 若可變,修改內容後 hashCode 需重算,緩存失效,Map 定位錯誤
  • 這是 String 成為 **Map Key 首選** 的關鍵性能優勢

原因三:安全性與線程安全

  • 線程安全:不可變對象天然線程安全,無需同步,多線程自由共享
  • 類加載安全:Class.forName("java.sql.Connection") 若可變被改為 "myhacked.Connection",後果災難性

總結:不可變性的五大收益

  1. 實現字符串常量池,節省堆內存
  2. 緩存 hashCode,提升 Map/Set 性能
  3. 天然線程安全,無鎖共享
  4. 參數傳遞安全,防篡改/注入攻擊
  5. 類加載機制安全,保證核心類正確性

設計啟示

不可變模式不僅適用於 String,**值對象、DTO、配置對象**均建議設計為不可變:
final 類 + final 字段 + 無 setter + 構造器/構建器注入 + 防禦性複製集合字段。
這是領域驅動設計(DDD)值對象模式的核心,也是並發編程「共享不可變」原則的直接應用。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
場景可變風險不可變保護
網絡連接 (URL、Host、Port)惡意修改導向釣魚地址參數傳遞過程中不可被篡改
文件路徑路徑遍歷攻擊 (../../etc/passwd)校驗後傳遞,中間不可竄改
反射參數 (類名、方法名)注入任意類/方法類加載器安全加載正確類
數據庫連接 (用戶名/密碼)竄改憑證認證過程不可繞過