Java 方法參數傳遞唯一採用按值傳遞。方法接收的是參數值的拷貝,無法修改調用者變量的內容——這對基本類型和引用類型均適用。
| 傳遞方式 | 傳遞內容 | 能否修改原變量 | 典型語言 |
|---|---|---|---|
| 按值傳遞 | 變量值的拷貝 | 不能 | Java、C、Python(不可變對象) |
| 按引用傳遞 | 變量的地址/別名 | 能 | C++、C#(ref/out) |
| 按指針傳遞 | 指針的拷貝 | 可修改指向內容,不可修改指針本身 | C、C++ |
方法接收值的拷貝,任何修改僅影響副本,原變量不變。
方法接收引用的拷貝(即對象地址的拷貝)。兩個引用指向同一堆對象,因此:
public class MyClass {
private Object num;
public MyClass(Object num) { this.num = num; }
public Object getNum() { return num; }
public void setNum(Object num) { this.num = num; }
}
public static void change(MyClass myClass) {
myClass.setNum(100); // 修改對象內部狀態
}
public static void main(String[] args) {
MyClass a = new MyClass(10);
System.out.println("調用前: " + a.getNum()); // 10
change(a);
System.out.println("調用後: " + a.getNum()); // 100 ✅
}
public static void swap(MyClass a, MyClass b) {
MyClass tmp = a;
a = b;
b = tmp; // 僅交換了局部引用副本
}
public static void main(String[] args) {
MyClass a = new MyClass(10);
MyClass b = new MyClass(100);
System.out.println("交換前 a: " + a.getNum()); // 10
System.out.println("交換前 b: " + b.getNum()); // 100
swap(a, b);
System.out.println("交換後 a: " + a.getNum()); // 10 ❌ 未變
System.out.println("交換後 b: " + b.getNum()); // 100 ❌ 未變
}
調用 change() 時:
main棧幀: a ──────► 堆對象 [num=10]
▲
change棧幀: myClass ┘ (引用拷貝,指向同一對象)
修改 myClass.num → 堆對象 [num=100] → main 中 a 看到變化
調用 swap() 時:
main棧幀: a ──────► 堆對象A [num=10]
b ──────► 堆對象B [num=100]
swap棧幀: a' ──────► 堆對象A (a的拷貝)
b' ──────► 堆對象B (b的拷貝)
交換 a'、b' 僅影響 swap 棧幀,main 棧幀 a、b 完全不受影響
既然無法交換引用,就交換對象內部狀態:
public static void swap(MyClass a, MyClass b) {
Object tmp = a.getNum();
a.setNum(b.getNum());
b.setNum(tmp); // 交換內部字段值
}
// 驗證
System.out.println("交換後 a: " + a.getNum()); // 100 ✅
System.out.println("交換後 b: " + b.getNum()); // 10 ✅
《Java 核心技術 卷Ⅰ》—— Cay S. Horstmann