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.da ta=2 tb.da ta=5
很多朋友郁闷,swap()函数也传递的是类,按照正常的经验,输出应该是:a.da ta=5 b.da ta=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的指向还是本身,其da ta值也没有变。其实指针变量也是一种变量类型,与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