基本概念卻讓很多人搞不清(包括我)。
首先在 java,函式的參數傳遞確實為 pass by value。
而 pass by value 代表當呼叫函式傳遞參數的時候,會複製參數的副本並傳入函式中,代表在函式內的參數和在函式外的變數是不同的。
所以在函式內部改變其值都不影響函式外部原先的變數。
在基本型別(boolean , char , byte , short , int , long , float , double)的情況很好理解。
@Test public void testInt() { int intNumber = 0; System.out.println("before increase: intNumber:"+intNumber); increase(intNumber); System.out.println("after increase: intNumber:"+intNumber); } private void increase(int number) { number++; System.out.println("in increase intNumber:"+number); }
output:
before increase: intNumber:0 in increase intNumber:1 after increase: intNumber:0
但如果是非基本型別,如物件或是陣列就要小心,因為這時候複製的副本是連結到物件的參考,而不是物件本身的副本。
也就是說傳入函式內的參考和和函式外部的參考連結到的是同一個物件,而因為連結的是同一個物件,所以在函式內改變了參考也會影響原先的物件。
情況就會完全不同。
為了方便示範,先建立一個Account 類別。
public class Account { private int mAge; private String mName; public Account(int age, String name){ mAge = age; mName = name; } public void setAge(int age) { mAge = age; } public void setName(String name) { mName = name; } public int getAge(){ return mAge; } public String getName() { return mName; } }
測試如下
@Test public void testAccount() { Account foxx = new Account(18, "foxx"); System.out.println("before foxx.getAge():"+foxx.getAge()+" foxx.getName()"+foxx.getName()); changeAccount(foxx); System.out.println("after foxx.getAge():"+foxx.getAge()+" foxx.getName():"+foxx.getName()); } private void changeAccount(Account account) { account.setAge(81); account.setName("new foxx"); System.out.println("in changeAccount account.getAge():"+account.getAge()+" account.getName():"+account.getName()); }
output:
before foxx.getAge():18 foxx.getName()foxx in changeAccount account.getAge():81 account.getName():new foxx after foxx.getAge():81 foxx.getName():new foxx
從輸出可以看到在函式中藉由參考修改了不同的數值也會影響原先外部的物件。
因此要小心在函式中的參考有什麼變化。修改 changeAccount 如下
private void changeAccount(Account account) { account = new Account(0, "zero"); System.out.println("in changeAccount account.getAge():"+account.getAge()+" account.getName():"+account.getName()); }
output:
before foxx.getAge():18 foxx.getName()foxx in changeAccount account.getAge():0 account.getName():zero after foxx.getAge():18 foxx.getName():foxx
因為在 changeAccount 的第3行我們讓傳進來的參考連結一個新的物件,因此在第3行之後的修改完全不會影響原先的物件。
補上 Array 以及 String 的測試
@Test public void testArray() { int[] intArray = new int[]{0,0,0}; System.out.println("before intArray[0]:"+intArray[0]+" intArray[1]:"+intArray[1]+" intArray[2]:"+intArray[2]); changeArray(intArray); System.out.println("after intArray[0]:"+intArray[0]+" intArray[1]:"+intArray[1]+" intArray[2]:"+intArray[2]); } private void changeArray(int[] intArray) { intArray[0] = 100; intArray[1] = 101; intArray[2] = 102; System.out.println("in changeArray intArray[0]:"+intArray[0]+" intArray[1]:"+intArray[1]+" intArray[2]:"+intArray[2]); }
output:
before intArray[0]:0 intArray[1]:0 intArray[2]:0 in changeArray intArray[0]:100 intArray[1]:101 intArray[2]:102 after intArray[0]:100 intArray[1]:101 intArray[2]:102
可以看到Array也是傳入參考的副本,所以在函式內的修改會影響原值。
String 的測試
@Test public void testString() { String name = "foxx"; System.out.println("before name:"+name); changeName(name); System.out.println("after name:"+name); } private void changeName(String name) { name = "xxof"; System.out.println("in changeName name:"+name); }
output:
before name:foxx in changeName name:xxof after name:foxx
String 的結果就不太一樣了,它雖然不是基本型別,但測試結果卻和基本型別一樣。
在函式內的修改不會影響原值。
再補上 Integer 的測試
@Test public void testInteger() { Integer integer = new Integer(10); System.out.println("before integer:"+integer); changeInteger(integer); System.out.println("after integer:"+integer); } private void changeInteger(Integer integer) { integer = Integer.MAX_VALUE; System.out.println("in change integer:"+integer); }
output:
before integer:10 in change integer:2147483647 after integer:10
看起來 Integer 也是和基本型別相同,在函式中的改變不會影響外部。