Call by value?


我們沒什麼不同 中談過了,Java的=運算,作用在基本型態與物件上並沒有什麼不同,無論是基本型態變數或類別型態所宣告的變數,使用指定運算時,都是將變數的值複製(指定)給另一個變數。

如果你這麼撰寫程式:
int x = 10;
int y = x;
Object o1 = new Object();
Object o2 = o1;

你作的是將x的值複製給y,所以y的值也是10,而如果o1儲存的值是0x1234,你作的是將0x1234指定給o2,所以o2儲存的值也是0x1234。

只不過Java不讓你直接處理記憶體位址,當你透過o1或o2操作物件時,會根據o1或o2儲存的位址值找到物件真正所在,然後操作它。

當你在方法呼叫時,其實也是這樣的行為,如果你這麼撰寫程式:
public void go() {
    int x = 10;
    some(x);
    System.out.println(x);
}
private void some(int y) {
   y = 100;
}

呼叫some()方法時,你作的是將x的值指定給參數y,而之後y改為100:


在C++中這種行為叫作Call by value。當作用於基本型態時,大部份人都不會有疑問。但下面這個程式會有人發出聲音:
public void go() {
    Customer c = new Customer();
    c.name = "Justin";
    some(c);
    System.out.println(c.name);
}
private void some(Customer cust) {
    cust.name = "caterpillar";
}

執行完go()方法之後,會顯示"caterpillar",在Java中,c這名稱被稱為參考(reference),然後有一點C++經驗就來學Java的,或者只是看到參考兩字的人就會說,這種叫作Call by reference,不過並不是事實,以C++的Call by value、Call by reference定義來說,Java沒有Call by reference,Java傳遞參數都只有Call by value。上面的程式,只不過是將c儲存的位址值指定給參數cust:


由於cust與c都是儲存相同的記憶體位址,當透過cust操作物件時,所操作的就是c所參考到的物件,因此改的name屬性也就是同一個物件的name屬性了,所以some()執行結束後,自然顯示c.name時,也就是修改為"caterpillar"的結果。

在Java中當你從方法中return一個物件時,其行為也是類似的,就不再多作說明了。

以C++中Call by value的定義來套用於Java的話,指的是Java在傳遞參數時,一律傳遞變數所儲存的值,無論是基本型態或是類別宣告的型態都一樣,Java中不允許處理記憶體位址,所以用了「參考」這個名稱來作為解釋類別型態所宣告的變數之行為,但這邊的「參考」與C++中所稱之「參考」,是完全不相同的行為,更不會有C++中 參數的傳 值、傳參考return 的傳值、傳參考 的Call by reference行為。