【解惑】Java方法參數是引用調用仍是值調用?

 最近找實習,在筆試時候作了下面這道題:求下面代碼的輸出結果。java

public class MyClass {

static void aMethod(StringBuffer sf1,StringBuffer sf2){
sf1.append(sf2);
sf2=sf1;
}

public static void main(String[] args){
StringBuffer sf1=new StringBuffer("A");
StringBuffer sf2=new StringBuffer("B");
aMethod(sf1,sf2);
System.out.println(sf1+":"+sf2);
}
}編程

我當時想到的輸出結果是:   AB:AB。   很顯然掉進出題人的圈套裏邊了,正確答案應該是AB:B。app

因爲長時間沒看JAVA,可能有些知識點生疏了,這道題就考了JAVA的值調用。函數

java程序設計語言中,方法參數的使用狀況要注意三點:this

●一個方法不能修改一個基本數據類型的參數(即數值型和布爾型)spa

●一個方法能夠改變一個對象參數的狀態設計

●一個方法不能實現讓對象參數引用一個新的對象。指針

爲了更好地理解,我看了一位博友的博客,內容以下:對象

轉載於:http://hxraid.iteye.com/blog/428856blog

方法調用(call by) 是一個標準的計算機科學術語。方法調用根據參數傳遞的狀況又分爲值調用( call by reference ) 引用調用( call by value ) 。江湖上有不少關於這兩種調用的定義 ,最一般的說法是傳遞值的是值調用,傳遞地址的是引用調用。這其實很不恰當,這種 這些說法很容易讓咱們聯想到Java的對象參數傳遞是引用調用,實際上,Java的對象參數傳遞仍然是值調用 。 


      咱們首先用一段代碼來證明一下爲何Java的對象參數傳遞 是值調用。

Java代碼   收藏代碼
  1. public class Employee {  
  2.   
  3.     public String name=null;  
  4.       
  5.     public Employee(String n){  
  6.         this.name=n;  
  7.     }  
  8.     //將兩個Employee對象交換  
  9.     public static void swap(Employee e1,Employee e2){  
  10.         Employee temp=e1;  
  11.         e1=e2;  
  12.         e2=temp;  
  13.                 System.out.println(e1.name+" "+e2.name); //打印結果:李四 張三  
  14.     }  
  15.     //主函數  
  16.     public static void main(String[] args) {  
  17.         Employee worker=new Employee("張三");  
  18.         Employee manager=new Employee("李四");  
  19.         swap(worker,manager);  
  20.         System.out.println(worker.name+" "+manager.name); //打印結果仍然是: 張三 李四  
  21.     }  
  22. }  

 

      上面的結果讓人很失望,雖然形參對象e1,e2的內容交換了,但實參對象worker,manager並無互換內容。這裏面最重要的緣由就在於形參e1,e2是實參worker,manager的地址拷貝。

      你們都知道,在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代碼吧!

C代碼   收藏代碼
  1. #include<stdio.h>  
  2. void swap(int *a1,int *b1){  
  3.     int *t=a1;  
  4.     a1=b1;  
  5.     b1=t;  
  6. }  
  7. int main(){  
  8.     int x1=100;  
  9.     int x2=200;  
  10.         int *a=&x1;  
  11.     int *b=&x2;  
  12.     printf("%d %d\n",*a,*b);  
  13.     swap(a,b);  
  14.     printf("%d %d\n",*a,*b);  
  15.     return 0;  
  16. }  

         但C/C++是有引用調用的,這就是C/C++一種叫作引用的變量聲明方法: int a; int &ra=a; 其中ra是a的別名,二者在內存中沒有區別,佔用了同一個內存空間。而經過引用(別名)的參數傳遞就符合引用調用的特色了。你們能夠去試試

void swap(int &a1,int &b1);的運行結果。

相關文章
相關標籤/搜索