java到底是值传递还是引用传递

原文:https://stackoverflow.com/questions/40480/is-java-pass-by-reference-or-pass-by-value

目录

高赞回答一:通过回答一能知道java是值传递还是引用传递

高赞回答二:通过回答二能理解值传递过程中的实质


对这个问题的理解,结合以下两个回答能清楚点,

请看:

高赞回答一:

java总是值传递的,当我们传递一个对象的值时,我们传递的是对象的引用,这就会让我们感到困惑(此处需结合回答二来理解)

比如:

public static void main(String[] args) {
    Dog aDog = new Dog("Max");
    Dog oldDog = aDog;

    // we pass the object to foo
    foo(aDog);
    // aDog variable is still pointing to the "Max" dog when foo(...) returns
    aDog.getName().equals("Max"); // true
    aDog.getName().equals("Fifi"); // false
    aDog == oldDog; // true
}

public static void foo(Dog d) {
    d.getName().equals("Max"); // true
    // change d inside of foo() to point to a new Dog instance "Fifi"
    d = new Dog("Fifi");
    d.getName().equals("Fifi"); // true
}

上例中,aDog.getName()会返回"Max",main方法中的aDog对象的值没有在foo方法中因为Dog("Fifi")改变值,由于对象引用是值传递。如果是引用传递,那么在调用了foo方法后,main方法中的aDog.getName()则会返回“Fifi”。

如下:

public static void main(String[] args) {
    Dog aDog = new Dog("Max");
    Dog oldDog = aDog;

    foo(aDog);
    // when foo(...) returns, the name of the dog has been changed to "Fifi"
    aDog.getName().equals("Fifi"); // true
    // but it is still the same dog:
    aDog == oldDog; // true
}

public static void foo(Dog d) {
    d.getName().equals("Max"); // true
    // this changes the name of d to be "Fifi"
    d.setName("Fifi");
}

上例中,Fifi是调用foo方法后aDog对象的name,因为对象的name在foo方法中被重新设置了。如何foo方法中对d的操作都如此,都是对aDog的操作,但是都不会改变aDog自身的值。(对于aDog自身的值和对aDog操作后属性的改变,此处可能看着很疑惑,请看回答二)

答主erlando个人主页:https://stackoverflow.com/users/4192/erlando

 

高赞回答二:

java spec中说到,Java中的一切均是值传递,java中并不存在引用传递

理解这个的关键在于

Dog myDog;

此处不是一个Dog对象,而是一个指向Dog对象的指针

(指针和引用的区别可参考https://www.cnblogs.com/dolphin0520/archive/2011/04/03/2004869.html

这是什么意思呢,如下:

Dog myDog = new Dog("Rover");
foo(myDog);

这个过程你本质上传递的将所创建Dog对象的地址给foo方法

(之所以说本质上,是因为java指针不是直接地址,但是把它当成地址是最好理解的)

假设Dog对象的存储地址是42,这就意味着我们传递了42给这个foo方法,如果方法如下定义:

public void foo(Dog someDog) {
    someDog.setName("Max");     // AAA
    someDog = new Dog("Fifi");  // BBB
    someDog.setName("Rowlf");   // CCC
}

我们看看发生了什么:

  • 参数someDog设值为42
  • 在AAA行,someDog指向的是地址42处所指向的Dog对象;地址42处所指向的Dog对象的name被修改为"Max"
  • 在BBB行,一个新的Dog对象被创建,我们假定它的地址是74,我们把参数someDog指定为74了
  • 在CCC行,someDog指向的是地址74行所指向的Dog对象;地址74行处所指向的Dog对象的name被修改为"Rowlf"
  • 之后,我们返回

现在来看方法外发生了什么:

myDog变了吗?

这就是关键。

记住myDog是一个指针,不是一个实际的Dog对象,因此myDog没变。myDog仍然是值为42,仍然指向原来的Dog对象,(但是注意,由于AAA行,它的name的值现在变为“Max”了,但还是同一个Dog对象,myDog的值没变)

通过地址来改变地址中的内容是完全有效的,但这不会改变地址这个变量。

在C++, Ada, Pascal和其他语言中,支持引用传递,你可以改变所传递的变量。

如果java中有引用传递的语义,那所定义的foo方法在BBB行时,将会改变myDog的指向。

引用变量是所传参数变量的别名,当别名被改变时,所传参数变量也同样被改变。

答主scott-stanchfield个人主页:https://stackoverflow.com/users/12541/scott-stanchfield

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值