HOWTO · Java

在 Java 中陣列是以值傳遞還是以引用傳遞

本文介紹了 Java 中檢查陣列是按值傳遞還是按引用傳遞。

本頁內容

Java 會以值傳遞每個方法引數。當引數是陣列時,複製到參數中的值是陣列物件的參考。因此,呼叫端的變數和方法參數可能指向同一個物件,但兩者仍是不同的變數。這就是為什麼變更陣列元素會讓呼叫端看見變化,而將另一個陣列指定給參數則不會。

Java 如何傳遞引數

參考是一種能讓程式存取物件的值;參考本身並不是物件。方法收到的是該參考值的副本。呼叫開始時,呼叫端的陣列變數和方法參數都指向同一個陣列物件。Java 不會以參考方式傳遞陣列變數本身,因此方法無法透過指定自己的參數來替換呼叫端的變數。

重點在於區分變更物件與變更變數。指定陣列元素會變更共用物件;指定方法參數則只會變更參數所持有的參考副本。即使這兩種操作都發生在被呼叫的方法中,結果仍然不同。

陣列元素變更如何影響呼叫端

方法寫入 values[index] 時,會變更兩個參考都能存取的陣列物件中的元素。方法返回後,呼叫端會看到該元素的變化。傳遞的仍是參考值的副本;元素變更之所以可見,是因為這個副本仍指向同一個物件。

方法重新指定陣列參數時會發生什麼事

將新陣列指定給方法參數後,該參數便會指向另一個物件。這不會改變呼叫端的變數;該變數仍指向原本的陣列。呼叫端可以看見重新指定之前對原始物件所做的變更,但不會取得參數的新參考。若要替換呼叫端的陣列變數,可以讓方法傳回新陣列,並在呼叫處指定傳回值;也可以直接變更原始陣列。

primitive 參數的行為

primitive 引數同樣以值傳遞:參數一開始取得的是 primitive 值的副本。如果方法將不同的數值指定給該參數,呼叫端的變數不會改變。這和重新指定陣列參數類似,與變更陣列元素不同。陣列的情況多了一個參考:這個參考值的副本可以用來變更共用物件,而指定新的參考只會影響區域參數。

執行以下自足範例:

本節中的程式碼以及顯示的標籤或輸出仍為英文。

public class ArrayArgumentDemo {
    static void changeFirst(int[] values) {
        values[0] = 9;
    }

    static void replaceParameter(int[] values) {
        values = new int[] {7, 8};
    }

    static void changeNumber(int number) {
        number = 9;
    }

    public static void main(String[] args) {
        int[] numbers = {1, 2};
        changeFirst(numbers);
        System.out.println(numbers[0]);
        replaceParameter(numbers);
        System.out.println(numbers[0]);

        int count = 1;
        changeNumber(count);
        System.out.println(count);
    }
}
9
9
1

第一個輸出顯示變更後的元素。第二個輸出顯示,方法參數被指定為另一個陣列後,呼叫端的陣列仍維持原狀。最後一個輸出則顯示,呼叫端的 primitive 變數也沒有改變。

重點整理

Java 一律以值傳遞引數,包括陣列參考。當呼叫端和方法參數指向同一個陣列物件時,元素變更會反映在呼叫端。重新指定參數只會改變它的區域參考;指定新值給 primitive 參數也只會改變它的區域副本。區分物件變更與參數指定,就能預測這些行為。