对于如下代码:
public class Test {
public static void main(String[] args) {
int i = 0 ;
Test test = new Test();
test.valueMethod(i);
System.out.println(i);
}
private void valueMethod(int a){
a = 5;
}
}
运行结果是0,由于参数是基本类型,因此调用时我们传递的是一个值,所以是java中的值传递,它传递的是一个值的副本,因此,在这个局部方法中对传进来的值的修改是不会影响外部变量的,它修改的是副本的值而不是外部成员i的值。
而对于如下代码
public class Test {
public static void main(String[] args) {
DO dos = new DO();
dos.setX1(3);
Test test = new Test();
test.paraMethod(dos);
System.out.println(dos.getX1());
}
private void paraMethod(Object o){
DO oo = (DO)o;
oo.setX1(5);
}
}
class DO{
private int x1 ;
public int getX1() {
return x1;
}
public void setX1(int x1) {
this.x1 = x1;
}
}
运行结果却是5,这是因为值传递时候,传递的是值的拷贝,而引用传递时,也是引用的拷贝,它意味着外部变量和局部变量的指针指向同一个对象,当你在局部方法内修改那个对象的值时,实际上是修改的堆中的值,因此外部变量的值也修改了
再看如下代码:
public class Test {
public static void main(String[] args) {
DO dos = new DO();
dos.setX1(3);
Test test = new Test();
test.paraMethod(dos);
System.out.println(dos.getX1());
}
private void paraMethod(Object o){
DO oo = new DO();
oo.setX1(8);
o = oo;
}
}
class DO{
private int x1 ;
public int getX1() {
return x1;
}
public void setX1(int x1) {
this.x1 = x1;
}
}
它的运行结果还是3,有的人就奇怪了,这个和第二个不是类似么,为什么这里没有修改它的值呢
其实知道画堆栈图的人把这里画出来就明白了
dos是栈中的一个引用,它指向了堆中的x1所代表的值3
1.当你用上面第2段代码时,实际上是拷贝了一个引用传递到局部方法中,我们暂且称这个引用为dos2,dos和dos2都指向了堆中的3,当我们修改dos2的值的时候实际上就是把这个3给改成了5,因此,dos的x1这个值就变成了5。
2.当你用上面第3段代码时,实际拷贝的是一个引用传递到局部方法中,我们也暂且称这个引用为dos2,dos和dos2都指向了堆中的3,现在我在局部方法体中重新定义了一个oo,这个oo又是一个栈中的指针,它指向了堆中的另外一个值为8的堆空间,我把这个引用赋给dos2时,实际上就只是把dos2的指针给变了,而dos继续指向它原来的3,因此最后的结果就为三拉。
最后总结一下,目前java传递有2种观点
一种是值传递观点,他们认为java只有值传递,没有引用传递,就算参数是一个引用,它也是引用值的副本,所以是值传递
另一种是基本类型为值传递,引用类型就是引用传递。
我个人比较支持第一种,不过这个一直都有争议,没有正确答案~~~~。