Java 唯一支援「值傳遞」。 所謂「引用傳遞」實為「傳遞引用的值」(傳遞物件參考的副本)。理解此點是避免 Java 參數傳遞誤區的關鍵。
class Number {
int i;
}
public class Assignment {
public static void main(String[] args) {
Number n1 = new Number();
Number n2 = new Number();
n1.i = 9;
n2.i = 47;
System.out.println("1: n1.i= " + n1.i + ", n2.i= " + n2.i);
n1 = n2; // 關鍵操作:參考重新指向
System.out.println("2: n1.i= " + n1.i + ", n2.i= " + n2.i);
n1.i = 27; // 透過 n1 修改物件內容
System.out.println("3: n1.i= " + n1.i + ", n2.i= " + n2.i);
}
}
1: n1.i= 9, n2.i= 47
2: n1.i= 47, n2.i= 47
3: n1.i= 27, n2.i= 27
Stack (main) Heap ┌──────────────┐ ┌──────────────┐ │ n1 ──────────┼────►│ Number obj │ │ │ │ i = 9 │ └──────────────┘ └──────────────┘ ┌──────────────┐ ┌──────────────┐ │ n2 ──────────┼────►│ Number obj │ │ │ │ i = 47 │ └──────────────┘ └──────────────┘
n1、n2 為區域變數 (儲存在 stack),各自持有指向不同 Number 物件的參考 (記憶體位址)。
n1 = n2 後 (步驟 2)
Stack (main) Heap
┌──────────────┐ ┌──────────────┐
│ n1 ──────────┼────┐│ Number obj │
│ │ ││ i = 9 │ (無參考指向,成 GC 目標)
└──────────────┘ │└──────────────┘
┌──────────────┐ │
│ n2 ──────────┼────┘
│ │ ┌──────────────┐
└──────────────┘ │ Number obj │
│ i = 47 │◄── n1、n2 共同指向同一物件
└──────────────┘
n1 = n2 將 n2 的參考值 (記憶體位址) **複製** 給 n1。此為「值傳遞」——傳遞的是參考的值,而非參考本身。原 n1 指向的物件失去參考,成為垃圾回收目標。
n1.i = 27 後 (步驟 3)Stack (main) Heap ┌──────────────┐ ┌──────────────┐ │ n1 ──────────┼────┐│ Number obj │ │ │ ││ i = 27 │◄── 透過任一參考修改,影響共享物件 └──────────────┘ │└──────────────┘ ┌──────────────┐ │ │ n2 ──────────┼────┘ │ │ └──────────────┘
n1、n2 指向同一物件,透過任一參考修改欄位,另一參考讀取時皆見更新值。這是「共享可變物件」特性,非「引用傳遞」。
void modifyPrimitive(int x) {
x = 20; // 修改副本
}
int a = 10;
modifyPrimitive(a);
// a 仍為 10
void modifyReference(Number num) {
num.i = 20; // ✅ 修改共享物件內容 - 可見
num = new Number(); // ❌ 修改區域參考指向 - 外部不可見
num.i = 30;
}
Number n = new Number();
n.i = 10;
modifyReference(n);
// n.i == 20 (第一行生效)
// n.i != 30 (第二行建立新物件,區域變數 num 指向新物件,外部 n 不受影響)
void swap(Number a, Number b) {
Number temp = a;
a = b;
b = temp; // 僅交換區域參考副本
}
Number n1 = new Number(); n1.i = 1;
Number n2 = new Number(); n2.i = 2;
swap(n1, n2);
// n1.i 仍為 1, n2.i 仍為 2
若需交換,必須回傳新物件、使用陣列/集合包裝、或設計可變容器類別。
| 概念 | 說明 | Java 是否支援 |
|---|---|---|
| 值傳遞 | 複製變數實際值 (基本型為資料值,參考型為記憶體位址) | ✅ 唯一機制 |
| 引用傳遞 | 傳遞變數別名,可在方法內修改呼叫端變數綁定的物件 | ❌ 不支援 |
| 共享可變物件 | 多參考指向同一物件,透過任一參考修改狀態皆可見 | ✅ 參考型別天然特性 |
| 參考副本 | 方法參數獲得呼叫端參考的複製品,指向同一物件 | ✅ 參數傳遞本質 |
Collections.unmodifiableList() 或副本Java 參數傳遞永遠是「值傳遞」。參考型別傳遞的是「指向物件的記憶體位址值」。方法內可透過此位址修改物件內容 (共享可變狀態),但無法讓呼叫端參考指向新物件。牢記此鐵律,即可精準預測所有參數傳遞行為。