在Java疑惑中通过引用传递

时间:2011-09-29 23:06:54

标签: java

所以我正在阅读this post并回复否。 2.在该示例中,在调用该方法之后,Dog值是否在地址42处,name更改为Max?

Dog myDog;

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

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

5 个答案:

答案 0 :(得分:6)

Java是基于值的传递 - 总是,对于基元和对象都是如此。

对于对象,传递的东西是对堆上存在的对象的引用。方法无法更改引用传入时引用的内容。

如果该引用指向具有可变数据的对象,则该方法可以改变其状态。

来自“Java编程语言第二版”,作者Ken Arnold和James Gosling(国际标准书号0-201-31006-6)(可能来自第40页 - 现在没有这本书的方便):

  

有些人会错误地说Java中的对象是“通过的   参考。“通过引用传递的术语适当地表示当a   参数传递给函数,调用函数得到一个   引用原始值,而不是其值的副本。如果   函数修改其参数,调用代码中的值将是   因为参数和参数使用相同的插槽而更改   记忆。 [...] Java中只有一个ParameterPassing模式 - pass   按价值 - 这有助于保持简单。

让我们看看你的例子(有一些改进):

public class Dog {

    private String name;

    public static void main(String [] args) {
        Dog myDog = new Dog("Rover");
        System.out.println("before foo: " + myDog);
        foo(myDog);
        System.out.println("after  foo: " + myDog);
    }

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

    public Dog(String n) { this.name = n; }

    public String getName() { return this.name; }

    public void setName(String n) { this.name = n; }

    public String toString() { return this.name; }
}

这是输出:

before foo: Rover
after  foo: Max

Tool completed successfully

您无法更改传递给foo的引用指向的内容,因此将其设置为BBB行名称为“Fifi”的引用,然后在CCC行更改该对象的名称,什么也没做。 <{1}}退出时,该实例有资格进行垃圾回收。

指向“Rover”的传入引用具有可变数据成员:其名称。在AAA行更改其值会反映在传入的引用中;因此产出不同。

答案 1 :(得分:2)

这可能是Java中大多数新手开发人员困惑的话题。 duffymo已经提供了一个详细的答案(我不打算重复),但我可以给你一些参考文章,我希望能从你的脑海中清除疑惑。

Jon Skeet关于Java中参数传递的article Pass-by-Value Please
Does Java pass by reference or pass by value?

HTH。

答案 2 :(得分:1)

  

要求Dog(地址为42的那个)将他的名字改为Max

答案 3 :(得分:0)

  

地址42处的狗值,名称是否更改为最大值?

是。 name更改

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

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

答案 4 :(得分:0)

myDogsomeDog共享同一个对象,并在开头包含相同的地址值。也就是说,两个变量都告诉JVM如何到达内存中的Object Dog(堆)。因此,如果您通过在setName上调用someDog方法来更改内容,myDog'会感觉到'效果!

someDog = new Dog("Fifi")创建新的Object Dog(Fifi)后,someDog变量包含Fifi的新值/地址。也就是说,someDog的值会发生变化,并告诉JVM从现在开始如何到达Fifi。此时,someDog上的每次更改都不会再影响myDog

检查我在该帖子上的答案(带图片的那个)并注意我这次没有使用“指针”这个词,甚至没有使用“引用”这个词! ;)