关于Java如何处理聚合和引用的困惑

时间:2018-08-18 21:33:18

标签: java reference aggregation

我对Java如何处理对象内的聚合(尤其是对象的引用)感到困惑。似乎当对象作为参数传递时,对象将保留对聚合对象的引用,而不是像我一直认为的那样复制它。

说我有一个名为Foo的基本类,它包含一个字符串属性,打印函数和用于文本属性的设置器。

public class Foo {

    private String text;

    public Foo(String text) {
        this.text = text;
    }

    public void print() {
        System.out.println(text);
    }

    public void setText(String text) {
        this.text = text;
    }

}

还有一个名为Bar的类,其中包含Foo类型的属性,以及一个名为print的方法,该方法调用foos打印方法。

public class Bar {

    private Foo foo;

    public Bar(Foo foo) {
        this.foo = foo;
    }

    public void print() {
        this.foo.print();
    }

}

如果我定义Foo的实例,请将其传递到Bar的新实例中,然后调用bar打印方法,它将按我的预期打印“ hello”。但是,如果我随后使用其setter方法将foo的原始实例的文本设置为“ Edited”,则bar打印方法也将打印“ Edited”。

public static void main(String[] args){

    Foo foo = new Foo("Hello");
    Bar bar = new Bar(foo);
    bar.print();
    foo.setText("Edited");
    bar.print();

}

Console Output

Bar对象似乎保留了对Foo对象的引用,即使我将其作为参数传递了。我确定我在这里缺少一些琐碎的东西,我只是想让别人清楚地解释一下。

2 个答案:

答案 0 :(得分:3)

“我确定我这里缺少一些琐碎的东西”

不是。您看到的不是错误,而是功能。在Java中传递对象意味着传递 对它们的引用 。除非代码通过.clone()明确请求,否则不会“克隆”对象。在此站点上搜索“是java传递值还是传递引用”应该可以帮助您找到所需的所有详细说明。

答案 1 :(得分:0)

引用已复制,不是对象

  

似乎当对象作为参数传递时,对象将保留对聚合对象的引用,而不是像我一直相信的那样复制它。

否,对象是 not 复制的

将引用(指针)作为参数传递给方法时将被复制。 not 不复制对象(指称对象,指针指向的对象)。

指针实际上是某个地方在内存中的地址(尽管我们的Java程序员并未看到)。该地址(基本上是一个数字)在传递给另一种方法时将被复制。但是该对象保持不变,不知道任何引用。

这是内存中几个Cat对象的图。五个中的三个是garbage-collection的候选者,因为它们没有剩余的引用,也没有指向它们的指针。首先,Lilly Mae猫有一个指向它的指针。

Cat c = new Cat( "Lilly Mae" ) ;

c变量不是持有Cat,它在内存中的其他位置保存了地址,您可以在其中找到Cat对象。想一想那行话:

variable-holding-pointer-that-can-only-point-to-objects-of-class-Cat c = instantiate-new-object-of-type-Cat-and-return-a-pointer-to-its-location-in-memory( "Lilly Mae" ) ;

然后我们将该指针作为参数传递给另一个方法。

Human h = SubservientHumanLocator.findFirstAvailable() ;
h.feedCat( c ) ;  // Passing a copy of the address of Lilly Mae to this other object’s method.

将对Cat的引用传递给Human之后,我们仍然只有一只饥饿的猫。我们没有克隆猫。现在,我们有两个引用,它们都指向相同的原始Cat对象。

这是Human::feedCat调用之前和之后的状态图。

enter image description here

在呼唤人类喂猫之后,变量c可能不在范围内。给猫喂食后,Human对象h可能会使其复制的参考也超出范围。然后,如果没有其他参考,并且没有剩余的现有参考,那么我们精心准备的Cat对象将成为垃圾收集的候选对象。