Java的所有對象都是引用,類似於C和C++中的指針。Java類的方法如果包含引用類型的參數,那麼當該方法被調用時,向該方法參數傳遞的是傳值變量的引用。不同於C和C++中的指針,Java對象在調用含參數方法時,向方法中的參數傳遞的都是指定的值得副本,而不是向參數傳值的變量本身。因此,在方法體重,如果參數的值被改變,不會影響向其傳值的變量的值。
來看一個具體的實例。
class ChangeStr {
private String myStr;
ChangeStr(String str) {
myStr = str;
}
public void setMyStr(String newStr) {
myStr = newStr;
}
public String toString() {
return myStr;
}
}
public class Test {
public static void main(String[] args) {
Test t = new Test();
System.out.println("==== Test 1 ====");
ChangeStr changeStr1 = new ChangeStr("Hello");
System.out.println(changeStr1);
t.change1(changeStr1);
System.out.println(changeStr1);
System.out.println();
System.out.println("==== Test 2 ====");
ChangeStr changeStr2 = new ChangeStr("Hello");
System.out.println(changeStr2);
t.change2(changeStr2);
System.out.println(changeStr2);
System.out.println();
}
// Method 1
public void change1(ChangeStr cs) {
cs.setMyStr("Hi");
cs = new ChangeStr("HaHa");
}
// Method 2
public void change2(ChangeStr cs) {
cs = new ChangeStr("HaHa");
cs.setMyStr("Hi");
}
}
類Test有兩個含參方法change1()和change2(),這兩個方法的不同之處在於,方法體兩個語句的順序不同。
程序輸出如下:
==== Test 1 ==== Hello Hi
==== Test 2 ==== Hello Hello |
從輸出結果可以看出,方法change1()改變了changeStr1的成員變量myStr的值,而change2()並沒有改變changeStr2的成員變量myStr的值。
針對test1,程序執行到第22行時,創建了一個ChangeStr實例changeStr1,並將其成員變量myStr賦值爲”Hello”,如圖所示。
當程序執行到第24行時,changeStr1的副本被傳遞給方法參數cs,這個副本的名字仍爲cs,這時cs與changeStr1指向同一個實體,見下圖:
在change1()方法體內,程序執行第38行時,cs調用方法setMyStr()改變了它所指向的實體的成員變量myStr的值,由於changeStr1與cs指向相同的實體,因此changteStr1的成員變量myStr的值便被更改爲”Hi”。
在change1()方法體內,程序執行第39行時,cs指向了一個新的實體,該實體的成員變量myStr的值爲”HaHa”,這對changeStr1無影響。
針對test2,程序執行到第29行時,與test1一樣,創建了一個ChangeStr實例changeStr2,並將其成員變量myStr賦值爲”Hello”,如圖所示。
同樣,當程序執行到第31行時,changeStr2的副本被傳遞給方法參數cs,這個副本的名字仍爲cs,這時cs與changeStr2指向同一個實體,見下圖:
在change2()方法體內,程序執行第44行時,與test1不同的是,這時cs指向了一個新的實體,該實體的成員變量myStr的值爲”HaHa”,而這對changeStr2無影響。
此後,當程序執行第45行時,cs調用方法setMyStr()改變了它所指向的實體的成員變量myStr的值,由於changeStr2與cs指向不同的實體,因此這對changteStr2仍然無影響。