按值調用(call by value)表示方法接收的是調用者提供的值。
按引用調用(call by reference)表示方法接收的是調用者提供的變量地址。
一個方法可以修改傳遞引用所對應的變量值,而不能修改傳遞值調用所對應的變量值。
Java總是採用按值調用,方法得到的是所有參數值的一個拷貝,方法不能修改傳遞給它的任何參數變量的內容。
eg.
public static void change(int x){
x++;
System.out.println("x = "+x);
}
public static void main(String[] args) {
int a = 1;
change(a);
System.out.println("a = "+a);
}
上面代碼執行後,輸出的結果如下
看一下具體的執行過程:
1.x被初始化爲a的一個拷貝,也就是1;
2.x執行x++後等於2,此時a依舊是1;
3.方法結束後,參數變量x不再使用。
方法參數共有兩種類型:基本數據類型和對象引用。已經看到,一個方法不能修改基本數據類型的參數,而對象引用作爲參數就不同了,看下面的例子
先建一個學生類,簡單的有姓名和年齡兩個屬性。
public class Student {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
}
利用下面方法實現年齡增長
public static void change(Student a){
a.setAge(a.getAge()+1);
System.out.println(a.getName()+"'s age is "+a.getAge());
}
public static void main(String[] args) {
Student stu = new Student("Stan",9);
System.out.println(stu.getName()+"'s age is "+stu.getAge());
change(stu);
System.out.println(stu.getName()+"'s age is "+stu.getAge());
}
上面代碼執行後,輸出的結果如下
已經看到,實現一個改變對象參數狀態的方法並不是一件難事,理由很簡單,方法得到的是對象引用的拷貝,對象引用及其拷貝同時引用一個對象。
看一下具體的執行過程:
1.a被初始化爲stu值的拷貝,這裏是對象的引用;
2.change方法應用於這個對象的引用,stu和a同時引用的那個Student對象的年齡+1;
3.方法結束後,參數變量a不再使用,而變量對象stu繼續引用那個年齡+1的學生對象。
回到最初的起點,很多程序設計語言提供了兩種參數傳遞的方式,就是文章開頭提到的按值調用和按引用調用,看到這裏可能大家認爲Java對對象採用的是按引用調用,實際上這種理解是錯誤的,文章開頭已經有了說明Java總是採用按值調用,方法得到的是所有參數值的一個拷貝,方法不能修改傳遞給它的任何參數變量的內容。
下面舉一個反例來闡述這個問題。
同樣是Student類,現在寫一個交換學生的方法。
public static void change(Student a,Student b){
Student temp = a;
a = b;
b = temp;
System.out.println("a's name is "+a.getName());
System.out.println("b's name is "+b.getName());
}
public static void main(String[] args) {
Student stu1 = new Student("Stan",9);
Student stu2 = new Student("Kyle",9);
System.out.println(stu1.getName()+"'s age is "+stu1.getAge());
System.out.println(stu2.getName()+"'s age is "+stu2.getAge());
change(stu1,stu2);
System.out.println(stu1.getName()+"'s age is "+stu1.getAge());
System.out.println(stu2.getName()+"'s age is "+stu2.getAge());
}
如果Java程序設計語言對對象調用採用的是按引用調用,那麼這個方法就應該能實現交換數據的效果,stu1變成Kyle而stu1變成Stan。但是讓我們看看執行結果
方法並沒有改變存儲在變量stu1和stu2中的對象的引用。change方法的參數a和b被初始化爲兩個對象引用的拷貝,這個方法交換的是這兩個拷貝,即a和b的引用發生了改變,相互引用了對方的對象,但stu1和stu2沒有改變,沒有對stu1和stu2產生影響。
最終,在方法結束時參數變量a和b被廢棄了,原來的變量stu1和stu2依然引用這個方法調用之前所引用的對象。
這個過程說明,Java程序設計語言對對象採用的不是按引用調用,實際上,對象引用進行的是值傳遞。即把引用的值傳遞進去賦值給參數,產生一個新的引用。
下面是總結:
1.一個方法不能修改一個基本數據類型的參數;
2.一個方法可以改變一個對象參數的狀態;
3.一個方法不能讓對象參數引用一個新的對象從而傳遞出來。