咱們首先用一段代碼來證明一下爲何Java的對象參數傳遞 是值調用。 html
public class Employee {
public String name=null;
public Employee(String n){
this.name=n;
}
//將兩個Employee對象交換
public static void swap(Employee e1,Employee e2){
Employee temp=e1;
e1=e2;
e2=temp;
System.out.println(e1.name+" "+e2.name); //打印結果:李四 張三
}
//主函數
public static void main(String[] args) {
Employee worker=new Employee("張三");
Employee manager=new Employee("李四");
swap(worker,manager);
System.out.println(worker.name+" "+manager.name); //打印結果仍然是: 張三 李四
}
}
上面的結果讓人很失望,雖然形參對象e1,e2的內容交換了,但實參對象worker,manager並無互換內容。這裏面最重要的緣由就在於形參e1,e2是實參worker,manager的地址拷貝。
你們都知道,在Java中對象變量名實際上表明的是對象在堆中的地址(專業術語叫作對象引用 )。在Java方法調用的時候,參數傳遞的是對象的引用。重要的是,形參和實參所佔的內存地址並不同,形參中的內容只是實參中存儲的對象引用的一份拷貝。 java多線程下載網絡資源
若是你們對JVM內存管理中Java棧 的局部變量區 有所瞭解的話(能夠參見《 Java 虛擬機體系結構 》),就很好理解上面這句話。在JVM運行上面的程序時,運行main方法和swap方法,會在Java棧中前後push兩個叫作棧幀 的內存空間。main棧幀中有一塊叫局部變量區的內存用來存儲實參對象worker和manager的引用。而swap棧幀中的局部變量區則存儲了形參對 象e1和e2的引用。雖然e1和e2的引用值分別與worker和manager相同,可是它們佔用了不一樣的內存空間。當e1和e2的引用發生交換時,下 面的圖很清晰的看出徹底不會影響worker和manager的引用值。
Java對象參數傳遞雖然傳遞的是地址(引用),但仍然是值調用。是時候須要給引用調用和值調用一個準確的定義了。
值調用(call by value) : 在參數傳遞過程當中,形參和實參佔用了兩個徹底不一樣的內存空間。形參所存儲的內容是實參存儲內容的一份拷貝。實際上,Java對象的傳遞就符合這個定義,只 不過形參和實參所儲存的內容並非常規意義上的變量值,而是變量的地址。咳,回過頭想一想:變量的地址不也是一種值嗎!
引用調用(call by reference) : 在參數傳遞的過程當中,形參和實參徹底是同一塊內存空間,二者不分彼此。 實際上,形參名和實參名只是編程中的不一樣符號,在程序運行過程當中,內存中存儲的空間纔是最重要的。不一樣的變量名並不能說明佔用的內存存儲空間不一樣。
大致上說,兩種調用的根本並不在於傳遞的是值仍是地址(畢竟地址也是一個值),而是在於形參和實參是否佔用同一塊內存空間。事實上,C/C++的指針參數傳遞也是值調用,不信試試下面的C代碼吧! java
#include<stdio.h>
void swap(int *a1,int *b1){ EMS指南
int *t=a1;
a1=b1;
b1=t;
}
int main(){
int x1=100;
int x2=200;
int *a=&x1;
int *b=&x2;
printf("%d %d\n",*a,*b);
swap(a,b);
printf("%d %d\n",*a,*b);
return 0;
}
編程