在 Java 中,方法呼叫時的參數傳遞永遠是值傳遞。這意味著:
public class PassTest {
float ptValue;
// 1. 傳遞基本型別 int
public void changeInt(int value) {
value = 55; // 修改區域副本
}
// 2. 傳遞不可變物件 String
public void changeStr(String value) {
value = new String("different"); // 區域參考指向新物件
}
// 3. 傳遞可變物件 PassTest
public void changeObjValue(PassTest ref) {
ref.ptValue = 99f; // 透過參考修改物件內部屬性
}
public static void main(String[] args) {
PassTest pt = new PassTest();
int val = 11;
String str = new String("Hello");
pt.changeInt(val);
System.out.println("Int value is: " + val); // 輸出 11
pt.changeStr(str);
System.out.println("Str value is: " + str); // 輸出 Hello
pt.ptValue = 101f;
pt.changeObjValue(pt);
System.out.println("Current ptValue is: " + pt.ptValue); // 輸出 99.0
}
}
| 情境 | 輸出 | 原因 |
|---|---|---|
基本型別 int | 11 | 方法修改的是區域副本,原變數 val 不變 |
不可變物件 String | Hello | 方法將區域參考指向新字串,原參考 str 仍指向 "Hello" |
可變物件 PassTest | 99.0 | 方法透過參考副本修改同一物件的 ptValue 屬性 |
C/C++ 開發者習慣用指標模擬引用傳遞(傳遞位址)。Java 移除了指標,但保留了參考概念。當傳遞物件參考時,雙方暫時指向同一記憶體位址,因此能修改物件內容,這不是引用傳遞,而是「傳遞參考的值」。
呼叫端: refA ──────► 物件A (ptValue=101)
│
▼ (傳遞參考值副本)
方法內: refB ──────► 物件A (ptValue=99) // 同一物件,屬性被修改
// 但若在方法內執行 refB = new PassTest();
// 則 refB 指向新物件,refA 仍指向原物件,互不影響
final 修飾參數,防止意外將區域參考指向新物件(編譯器會檢查)。String、Integer 等不可變類別的特性,避免誤以為能修改原物件。一句話總結:Java 只有值傳遞;傳物件時傳的是「遙控器副本」,能操作物件,但換不掉呼叫端手中的遙控器。