CodeGym /課程 /JAVA 25 SELF /參數的值傳遞與參考傳遞

參數的值傳遞與參考傳遞

JAVA 25 SELF
等級 8 , 課堂 4
開放

1. 介紹

在各種程式語言中,將參數傳入函式(或方法)主要有兩種方式:

  • 值傳遞:函式收到的是變數值的副本。若函式改變參數,原始變數不會改變。
  • 參考傳遞:函式接收原始物件的「參考」(指標)。在函式內的變更會反映到原始物件。

在 Java 中,所有參數一律是值傳遞!
但有個眉角:當我們傳遞基本型別(intdoubleboolean 等)時,複製的是值本身。而當傳遞參考型別(例如陣列或物件)時,複製的是參考的值(也就是記憶體中物件的「位址」),而不是物件本身。

如果你覺得腦袋開始融化,別擔心——我們現在就條理化並用範例來說明!

2. 基本型別:複製的是值

先從簡單的開始:如果我們試著在方法內改變 int 型別變數的值,會發生什麼事?

public class Demo 
{
    public static void main(String[] args) 
    {
        int number = 5;
        changeValue(number);
        System.out.println(number); // 會印出什麼?
    }

    public static void changeValue(int n) 
    {
        n = 42;
    }
}

結果:畫面會印出5

為什麼?
傳入 changeValue 方法的是變數 number 的值的副本。在方法內我們只改到副本(n),位於 main 的原始變數 number 不會被動到。

比喻
想像你給了朋友護照的影本,而不是正本。朋友愛怎麼在影本上畫鬍子都行——你的真正護照還是原樣!

3. 參考型別:複製的是參考

現在用陣列試試看:

public class Demo 
{
    public static void main(String[] args) 
    {
        int[] numbers = {1, 2, 3};
        changeFirst(numbers);
        System.out.println(numbers[0]); // 會印出什麼?
    }

    public static void changeFirst(int[] arr) 
    {
        arr[0] = 99;
    }
}

結果:畫面會印出99

為什麼?
傳入 changeFirst 方法的是指向陣列 numbers 的參考的副本。兩個名稱(main 中的 numbers 與方法裡的 arr)都指向記憶體中的同一個陣列。因此在方法內改變陣列元素,外面也「看得到」。

視覺化

main: numbers ──► [1, 2, 3]
                   ▲
                   │
changeFirst: arr ──┘
參考的副本仍指向記憶體中的同一個物件

當我們改變 arr[0],其實就是在改 numbers[0],因為兩者都指向同一個物件。

4. 但如果改變參考本身——原來的物件不會改變!

來試試看這樣做:

public class Demo 
{
    public static void main(String[] args) 
    {
        int[] numbers = {1, 2, 3};
        replaceArray(numbers);
        System.out.println(numbers[0]); // 會印出什麼?
    }

    public static void replaceArray(int[] arr) 
    {
        arr = new int[] {10, 20, 30};
    }
}

結果:會印出1

為什麼?
replaceArray 方法裡,變數 arr 轉而指向新陣列,但這不會影響 main 中的變數 numbers
它們原本共用同一個參考,不過當我們在方法內指派 arr = ... 時,這只是區域性的變更。

比喻
這就好比你和朋友原本拿的是同一把房門鑰匙。朋友另外配了一把新鑰匙,但你手上的舊鑰匙仍然不變,門也還是同一扇。

5. 加深練習:無法透過方法把兩個 int「互換」

許多新手嘗試撰寫一個把兩個數字交換的位置的方法,但結果行不通:

public class Demo 
{
    public static void main(String[] args) 
    {
        int a = 5, b = 10;
        swap(a, b);
        System.out.println(a + " " + b); // 預期:10 5,那實際呢?
    }

    public static void swap(int x, int y) 
    {
        int temp = x;
        x = y;
        y = temp;
    }
}

結果:畫面會印出5 10

為什麼?
因為進到 swap 的,是變數 ab 的副本。我們在 swap 裡做的一切,只會影響這些副本,而不是原始變數。

6. 但對陣列可以改變其內容!

來看用陣列正確地交換數值的方法:

public class Demo 
{
    public static void main(String[] args) 
    {
        int[] arr = {5, 10};
        swap(arr);
        System.out.println(arr[0] + " " + arr[1]); // 預期:10 5
    }

    public static void swap(int[] arr) 
    {
        int temp = arr[0];
        arr[0] = arr[1];
        arr[1] = temp;
    }
}

結果:會印出10 5

為什麼?
因為我們改的是物件(陣列)的內容,而呼叫端的原始變數與方法參數都指向同一個物件。

7. 示範:物件與其欄位

陣列說明完了,那自訂類別的物件呢?完全一樣!

class Box 
{
    int value;
}

public class Demo
{
    public static void main(String[] args) 
    {
        Box box = new Box();
        box.value = 7;
        changeBox(box);
        System.out.println(box.value); // 會印出什麼?
    }

    public static void changeBox(Box b) 
    {
        b.value = 42;
    }
}

結果:會印出42

為什麼?
因為我們改的是參考所指向物件的欄位。

將參數傳入方法時會發生什麼

傳入的是 複製的是 可在方法內改變嗎? 外部看得到變更嗎?
intdouble 值的副本 可以,但只能改到副本 不會
陣列 參考的副本 可以,若變更元素
物件(類別) 參考的副本 可以,若變更欄位
陣列/物件 參考的副本 不會,若只是指派新的參考 不會

8. 常見錯誤

錯誤 1:期待 int 在呼叫方法後會改變。 許多新手以為把 int 變數傳進方法後,就能在方法裡改掉它的值。這是錯的:改到的只有副本!

錯誤 2:嘗試用方法把兩個 int 互換。 如我們已經看到的,這做不到——只有變數的副本在互換,原始變數不受影響。

錯誤 3:嘗試透過方法「替換」陣列。 如果你在方法內把參數陣列指派成新的陣列(arr = new int[]{...}),這不會影響原本的陣列。若要「替換」陣列——需要由方法回傳新的陣列,並在呼叫端把它指派給變數。

錯誤 4:忘了可以改物件的內容。 若你傳的是物件(或陣列),別忘了:對其欄位/元素的任何變更都會在外面看得到!

錯誤 5:與 null 搞混。 如果傳進方法的參考是 null,還嘗試存取其欄位——就會得到 NullPointerException。請小心!

留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION