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=
2
n=
3
m=
2
n=
3
------直接交換----------
a=
2
b=
3
a=
2
b=
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
-------數組交換---------
2
3
3
2
-----類本身內交換-------
a=
2
b=
3
a=
3
b=
2