Java 只有值傳遞。但「值」的含義不同:
public class ParameterPassingDemo {
String str = "hello";
char[] ch = {'a', 'b'};
public static void main(String[] args) {
ParameterPassingDemo demo = new ParameterPassingDemo();
System.out.println("調用前:str=" + demo.str + ", ch=" + Arrays.toString(demo.ch));
demo.change(demo.str, demo.ch);
System.out.println("調用後:str=" + demo.str + ", ch=" + Arrays.toString(demo.ch));
}
public void change(String str, char[] ch) {
str = "test ok"; // 修改局部引用指向新對象
ch[0] = 'c'; // 通過引用修改數組內容
}
}
// 輸出:
// 調用前:str=hello, ch=[a, b]
// 調用後:str=hello, ch=[c, b]
調用前:
main棧幀 堆內存
str ──────────► "hello" (String對象)
ch ──────────► [a, b] (char數組)
調用 change() 時:
change棧幀
str (副本) ───► "hello" (同一對象)
ch (副本) ───► [a, b] (同一數組)
執行 str = "test ok":
change棧幀
str ────────► "test ok" (新對象,main 的 str 不受影響)
執行 ch[0] = 'c':
堆內存
[a, b] 變為 [c, b] (main 和 change 共享同一數組,均可見變化)
| 操作 | String (不可變對象) | char[] (可變數組) |
|---|---|---|
| 重新賦值參數變量 | 只影響局部引用,原對象不變 | 只影響局部引用,原數組不變 |
| 調用修改方法 (如 setCharAt) | 無此方法,String 不可變 | 修改共享對象內容,調用方可見 |
| 調用 replace/substring | 返回新字符串,原對象不變 | N/A |
// 錯誤:直接暴露內部數組引用
public char[] getChars() { return this.ch; }
// 正確:返回副本
public char[] getChars() { return Arrays.copyOf(this.ch, this.ch.length); }
public void process(final String input, final char[] data) {
// input = "new"; // 編譯錯誤
// data = new char[10]; // 編譯錯誤
data[0] = 'x'; // 允許:修改對象內容
}
Q: 如何在方法中修改實參 String 的值?
A: 不可能。String 不可變,且 Java 是值傳遞。只能返回新字符串由調用方接收。
Q: 為什麼數組修改生效了?
A: 傳遞的是數組引用的副本,副本指向同一堆內存地址,通過副本修改內容自然可見。
Java 嚴格遵循值傳遞。理解「引用的值」即內存地址,是掌握參數傳遞本質的關鍵。不可變對象天然安全,可變對象需通過防禦性拷貝、final 參數、不可變集合等手段管控副作用。