「Java 是值傳遞還是引用傳遞?」 這個問題困擾了無數初學者。本文從 JVM 內存模型、棧幀結構、對象引用本質三個維度,徹底釐清 Java 參數傳遞機制。
Java 只有值傳遞。傳遞基本類型時複製值本身;傳遞引用類型時複製引用的值(即對象地址),而非對象本身。
void changeInt(int value) {
value = 55; // 修改棧帧局部變量表槽位的值
}
int val = 11;
changeInt(val); // 實參 val 的值 (11) 複製給形參 value
// val 仍為 11
void changeObj(PassTest ref) {
ref.ptValue = 99f; // 通過引用修改堆上對象字段
}
PassTest pt = new PassTest();
pt.ptValue = 101f;
changeObj(pt); // 實參 pt 的引用值 (地址) 複製給形參 ref
// pt.ptValue 變為 99f
pt 在棧上,存儲對象在堆中的地址。ref,兩個引用指向同一個堆對象。void changeStr(String value) {
value = new String("different"); // 形參 value 指向新對象
}
String str = "Hello";
changeStr(str);
// str 仍指向 "Hello",未變
value = new String(...) 只是修改局部引用變量 指向,不影響實參引用。| 語言 | 機制 | 能否修改實參引用指向 |
|---|---|---|
| C | 值傳遞 (可傳指針地址) | ✅ void f(int **p) |
| C++ | 引用傳遞 / 指針傳遞 | ✅ void f(int*& p) |
| Java | 值傳遞 (引用值不可變) | ❌ 無語法機制修改實參引用 |
String、Integer、LocalDate 等不可變類,傳遞安全,無副作用。StringBuilder 等,明確文檔所有權:是調用方負責不可變性,還是被調用方可修改?public void setList(List list) {
this.list = new ArrayList<>(list); // 防禦性拷貝
} obj = new Obj() 無效,應返回新對象或使用包裝類/數組/AtomicReference。Java 參數傳遞 = 值傳遞。理解「引用值複製」與「對象共享」的邊界,是寫出無副作用、線程安全代碼的基石。