首先非常确定地说:如果你对“传引用”、“传值”的理解是来源于C 或 C++中指针问题的话,那么Java的参数传递就是传值!
想到考虑这个问题是在读java.util的Timer源码时看到了这几条语句
TimerTask tmp = queue[j]; queue[j] = queue[k]; queue[k] = tmp;刚一看是正常的交换语句,但一想难道不是“Java的所有对象皆为引用”吗?这样的话tmp就和queue[j]是同一个引用,queue[j] = queue[k]时不应该也相当于tmp = queue[k]吗?为什么能够完成交换呢?
之后自己也写了类似的测试,果然可以交换!然后把交换部分写在一个方法里,像这样
public class Main
{
public static void main(String[] args)
{
copyTest();
}
private static void copyTest()
{
A a1 = new A(1);
A a2 = new A(2);
A tmp = a1;
a1 = a2;
a2 = tmp;
System.out.println("*******after swapping*******");
System.out.println("a1 = " + a1.id);
System.out.println("a2 = " + a2.id);
/*************/
a1 = new A(1);
a2 = new A(2);
swap(a1, a2);
System.out.println("*******after swapping in function*******");
System.out.println("a1 = " + a1.id);
System.out.println("a2 = " + a2.id);
}
private static void swap(A o1, A o2)
{
A tmp = o1;
o1 = o2;
o2 = tmp;
}
}
class A
{
public int id = 0;
public A(int id)
{
this.id = id;
}
}
结果是:
*******after swapping*******
a1 = 2
a2 = 1
*******after swapping in function*******
a1 = 1
a2 = 2
也就是在方法中没有完成交换!到这里突然感觉自己非常LOW逼,因为大一什么都不懂的时候还在来回的倒腾关于传值传指针传引用的问题,现在Java写了这么长时间(相对于更短暂的写C的时间而言)竟然还没搞懂Java方法传参是传值还是传引用的问题。
于是只能去搜索,在网上找到一篇很不错的讲解:http://blog.csdn.net/wyzsc/article/details/6341107
其中所说也终于解开了我的迷惑:Java向方法传递参数时传递的是值,引用的值,就像C/C++中传地址一样,传递过去地址被形式参数复制出了独立的一份。
当程序运行到
private static void swap(A o1, A o2)时,内存中应该是这个样子:
执行到这一句
A tmp = o1;内存中应该是这个样子:
当运行到
o1 = o2;内存中应该是这个样子:
当运行到这一句
o2 = tmp;内存中应该是这个样子:
至此交换完成,从图中明显可以看出:虽然参数o1、o2完成了交换,但那其实只是他们指向的内存区域的箭头发生了变化,即参数传递是传值,并非是他们所指向的内存区域发生了变化,即传引用。
同样我写了一段C++的代码
#include
using namespace std;
class A
{
public:
int id = 0;
A(int tid)
{
id = tid;
}
};
void mySwapByValue(A o1, A o2)
{
A tmp = o1;
o1 = o2;
o2 = tmp;
}
void mySwapByReference(A &o1, A &o2)
{
A tmp = o1;
o1 = o2;
o2 = tmp;
}
void mySwapByCopyingAddress(A *o1, A *o2)
{
A *tmp = o1;
o1 = o2;
o2 = tmp;
}
int main()
{
A a1 = NULL;
A a2 = NULL;
/*********************part1**************************/
a1 = A(1);
a2 = A(2);
A tmp = a1;
a1 = a2;
a2 = tmp;
cout << "*********after swapping************" << endl;
cout << "a1 = " << a1.id << endl;
cout << "a2 = " << a2.id << endl;
/****************************************************/
/*********************part2**************************/
a1 = A(1);
a2 = A(2);
mySwapByValue(a1, a2);
cout << "*********after swapping in mySwapByValue************" << endl;
cout << "a1 = " << a1.id << endl;
cout << "a2 = " << a2.id << endl;
/****************************************************/
/*********************part3**************************/
a1 = A(1);
a2 = A(2);
mySwapByReference(a1, a2);
cout << "*********after swapping in mySwapByReference************" << endl;
cout << "a1 = " << a1.id << endl;
cout << "a2 = " << a2.id << endl;
/****************************************************/
/*********************part3**************************/
a1 = A(1);
a2 = A(2);
mySwapByCopyingAddress(&a1, &a2);
cout << "*********after swapping in mySwapByCopyingAddress************" << endl;
cout << "a1 = " << a1.id << endl;
cout << "a2 = " << a2.id << endl;
/****************************************************/
return 0;
}
运行结果是:
*********after swapping************
a1 = 2
a2 = 1
*********after swapping in mySwapByValue************
a1 = 1
a2 = 2
*********after swapping in mySwapByReference************
a1 = 2
a2 = 1
*********after swapping in mySwapByCopyingAddress************
a1 = 1
a2 = 2
上述Java中的交换方法非常类似于这段C++代码中的mySwapByCopyingAddress函数。实质也是传值,传递引用的值。
因此,Java方法的参数传递是传值并非传引用。