JAVA中的參數傳遞

    JAVA的許多教材中提到:java中沒有引用傳遞,只有值傳遞。因此爲了實現C++等語言中的引用,JAVA中提供瞭如下的引用類型:數組、類(包括對象)、接口、枚舉。 
    但許多朋友卻遇到這樣的問題:在交換兩個數的程序中,用JAVA中的類來進行參數傳遞同樣無法交換兩個變量的值,好像還是值傳遞,而不是引用傳遞。           
    下面首先引入一段程序:Code1:
public class Test
{
public int data;
public Test(int data){this.data = data;}

public static void swap(Test a, Test b)
{Test tmp= a;a = b;b = tmp;}

public static void main(String[] args)
{ Test ta=new Test(2); Test tb=new Test(5);
 Test.swap(ta, tb);
System.out.println("ta.data="+ta.data+"\t"+"tb.data="+tb.data);
}
}

 

     
本程序的輸出結果是:ta.data=2        tb.data=5
   很多朋友鬱悶,swap()函數也傳遞的是類,按照正常的經驗,輸出應該是:a.data=5       b.data=2 纔是,可結果卻令人大跌眼鏡。其實教材上並沒有問題,機器運行的結果永遠是最好的證明,還是我們對引用傳遞的機制理解的太淺顯所致。
   本程序中swap()函數傳遞的是Test類型,但其實實現的還是按值傳遞的機制。這可以和C語言類比,C中也沒有真正的引用傳遞,只有值傳遞,只是藉助指針間接地實現了引用傳遞。這裏首先說明C語言中的一個指針的例子:int a=20;int *p=&a;這裏p是一個指針型變量,a的內容是一個int型的值20,p的內容是一個指針(a變量的的地址3F60),這樣就可以用*p訪問a了(若單從訪問20這個數來看,用指針訪問時系統似乎另外分配了一個存放地址的單元,不同編譯器對此分配不同的單元,Turbo C++中指針變量本身佔用2個字節,VC++中指針變量本身佔用4個字節的存儲空間。有關指針的詳細知識請參考相關資料)。
 
   在C語言中,定義 void swap(int *a,int *b){int temp; temp=*a;  *a=*b;   *b=temp;}    這樣的函數,調用swap(&a,&b)來實現引用傳遞,從而成功交換兩個變量的值。
   再來說上述的JAVA程序,JAVA中的類、對象、數組什麼的在當做參數時可以看做是C、C++中的地址(或指針)。雖然 public static void swap(Test a, Test b)的參數是Test類,但在函數體內其實也只是對指針變量內容的交換(即還是指針變量內容的直接交換),而不是指針變量指向的單元內容的交換(注意:JAVA中沒有指針的概念,此處只是爲了理解暫且這麼說)。這裏的Test a相當於上述C語言中的指針變量p,通過public static void swap(Test a, Test b)函數只是改變了p的內容(即p內容中的3F60),但當函數條用完畢後,局部變量自動撤銷,故ta和tb的指向還是本身,其data值也沒有變。其實指針變量也是一種變量類型,與int、double一樣,上述就可以看做是兩個int型的變量,這樣就很容易看出是值傳遞而不是引用傳遞。而上面的C語言函數void swap(int *a,int *b)    {int temp;     temp=*a;    *a=*b;     *b=temp;}    卻是改變的是*p的內容(即p指向的3F60單元的值20),而調用時swap(&a,&b)傳遞的是a,b的地址,故當調用結束是a,b的地址未變(如a的地址還是3F60),變化的是a,b存儲單元的內容的值,從而使兩個變量的交換。讀者請仔細分析其中的差別,理解上述程序的錯誤所在。
 
   同樣以下的程序結果也可用上述的說明來解釋:由於StringBuffer是系統類,但y=x知識改變y的內容,而不是改變其指向的單元的內容;而x.append(y)卻x的地址不變而其指向的單元內容改變(讀者可查看StringBuffer與String的不同)。Code2:
 
public class Test {
    public static void main(String [ ] args) {
        StringBuffer a = new StringBuffer("A");
        StringBuffer b = new StringBuffer("B");
        change(a , b);
        System.out.println(a + "," + b);
    }
    static void change(StringBuffer x , StringBuffer y) {
        x.append(y);
        y = x;
    }
}

 

結果顯示:  AB , B

 

下面給出JAVA中的兩個變量的其他交換示例,來說明JAVA中的值傳遞與引用傳遞的機制。

public class SwapNumbers {   
    public int a;   
    public int b;   
       
    public SwapNumbers(int a,int b){
    	this.a=a;  this.b=b;
    }
    
    //包裝類交換   
    public static void swap (Integer a, Integer b) {       
        Integer temp = a;   
        a = b;   
        b = temp;   
    };   
       
    //直接交換   
    public static void swap (int a, int b) {       
        int temp = a;   
        a = b;   
        b = temp;   
    };   
       
    //對象成員交換  
    public static void swap (SwapNumbers a,SwapNumbers b) {       
        int tempa = a.a,tempb=a.b;   
        a.a =b.a;  a.b=b.b; 
        b.a = tempa;  b.b=tempb; 
    }; 
    
    //數組   
    public static void swap (int[] arr) {      
        int temp = arr[0];   
        arr[0] = arr[1];   
        arr[1] = temp;   
    };   
       
    //類本身內交換  
    public  void swapNum(int a, int b) {       
        this.a = b;   
        this.b = a;   
    };   
       
    //包裝類打印   
    public static void print(Integer m, Integer n) {   
        System.out.println("m=" + m.intValue() + " n=" + n.intValue());   
    }   
    //直接打印   
    public static void print(int a, int b) {   
        System.out.println("a=" + a + " b=" + b);   
    }   
    //對象打印   
    public static void print(SwapNumbers a,SwapNumbers b) {   
        System.out.println("a.a=" + a.a + "  a.b=" + a.b+"\t"+"b.a=" + b.a + "  b.b=" + b.b);   
    }   
    //數組打印   
    public static void print(int[] a) {   
        for (int i : a) {   
            System.out.print(i + " ");   
        }   
        System.out.println();   
    }   
    //類本身打印
    public void print() {   
        System.out.println("a=" + this.a + " b=" + this.b);   
    } 
       
    public static void main(String[] args) {   
                           
        System.out.println("------包裝類交換--------");   
        Integer m = new Integer(2);   
        Integer n = new Integer(3);        
             
        print(m,n);   
        swap(m, n);   
        print(m,n);  
        
        System.out.println("------直接交換----------");   
        int a = 2, b = 3;   
           
        print(a,b);   
        swap(a, b);   
        print(a,b);   
        
        System.out.println("-----對象成員交換-------");   
        SwapNumbers oa = new SwapNumbers(2,3); 
        SwapNumbers ob = new SwapNumbers(4,5);
           
        print(oa,ob);   
        swap(oa, ob);   
        print(oa,ob);   
           
        System.out.println("-------數組交換---------");   
        int[] arr = {2,3};   
        print(arr);   
        swap(arr);   
        print(arr);   
           
        System.out.println("-----類本身內交換-------");   
        print(a,b);   
        SwapNumbers sn = new SwapNumbers(2,3);   
        sn.swapNum(a, b);   
        sn.print();   
           
    }   
} 


輸出結果:

 

 

------包裝類交換--------
m=2n=3
m=2n=3
------直接交換----------
a=2b=3
a=2b=3
-----對象成員交換-------
a.a=2 a.b=3   b.a=4  b.b=5
a.a=4 a.b=5   b.a=2  b.b=3
-------數組交換---------
23 
32 
-----類本身內交換-------
a=2b=3
a=3b=2

 

 

 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章