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

Java String 不可變性原理與 replace 陷阱

     編輯:Java 綜合教學

核心結論

String 對象一旦創建,內容永不可變。所有「修改」操作(replace、substring、concat、toUpperCase 等)都會返回新 String 對象,原對象不變。

代碼驗證

String str3 = "LOVO JAVA";
str3.replaceAll("JAVA", "J2EE");           // 返回新對象,未賦值則丟棄
System.out.println(str3);  // 輸出:LOVO JAVA  (原對象未變)

String str4 = str3.replaceAll("JAVA", "J2EE");
System.out.println(str4);  // 輸出:LOVO J2EE  (新對象)

內存圖解

String s1 = "abc";
String s2 = s1.replace('a', 'x');

Heap:
┌─────────────┐     ┌─────────────┐
│ "abc"  ← s1 │     │ "xbc"  ← s2 │
└─────────────┘     └─────────────┘
  原對象不變          新對象

源碼級證據 (JDK 17)

public String replace(char oldChar, char newChar) {
    if (oldChar == newChar) return this;  // 無實際變化返回自身
    char[] val = value.clone();           // 複製底層 char[]/byte[]
    for (int i = 0; i < val.length; i++) {
        if (val[i] == oldChar) val[i] = newChar;
    }
    return new String(val);               // 封裝新數組返回新 String
}

性能陷阱:字串拼接循環

// ❌ 違反:每次循環創建新 StringBuilder + 新 String,O(n²)
String s = "";
for (int i = 0; i < 10000; i++) s += "a";  

// ✅ 正確:單一 StringBuilder,O(n)
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10000; i++) sb.append("a");
String s = sb.toString();

// Java 9+ 編譯器優化:+ 會自動轉為 StringBuilder,但顯式更可控

不可變性帶來的優勢

  • 線程安全:無狀態,天然可共享
  • 字串常量池:相同字面量複用,節省內存
  • HashCode 緩存:hash 欄位懶加載,Map/Set 鍵高效
  • 安全性:網絡路徑、SQL 參數、文件路徑不可被篡改

相關類對比

面試高頻題

  1. String s = "a" + "b"; 創建幾個對象?
    → 1 個,編譯期常量折疊為 "ab"
  2. String s = new String("a") + new String("b"); 創建幾個對象?
    → 3-4 個:兩個 new String、一個 StringBuilder、一個結果 String(+ 常量池 "a","b")
  3. 為什麼 String 設計為 final?
    → 防止繼承破壞不可變性契約,保證安全性與優化

牢記:String 操作必須接收返回值,否則等於白操作。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
類可變性線程安全適用場景
String不可變是常量、鍵值、少量拼接
StringBuilder可變否單線程大量拼接
StringBuffer可變是多線程大量拼接 (較慢)