返回私有成员时,返回值是对该成员的直接引用还是单独的副本?

When returning a private member, is the returned value a direct reference to the member or a separate copy?

为了阐明这一点,请考虑以下代码:

public class Foo {
    private Object thing;

    public Foo() { ... }

    public Object getThing() {
        return this.thing;
    }
}

public class Bar {
    public Bar() { ... }

    public Object makeNewThing() { ... }

    public void changeThing() {
        Foo foo = new Foo();
        Object thing = foo.getThing();
        thing = makeNewThing();
    }
}

Barmutates修改了从foo.getThing()接收到的Object的值时,是[=14中的原始私有成员=] 突变 修改?

编辑:一些话

getThing()返回的东西是对私有变量thing

引用

如需修改,使用foo.getThing().doSomeMethod()

您目前在 changeThing 中所做的事情:获取对 foo 的引用并将其分配给方法变量 thing。然后你给变量 thing 赋值一个完全不同的东西。 不会更改实例中的任何内容foo

是的,如果您 实际上 改变对象, foo 中的原始成员就会改变。目前你只是重新分配你持有的变量,它不会对对象本身执行任何操作。

考虑一下

public class Foo {
    private FooInner thing = new FooInner();

    public FooInner getThing() {
        return this.thing;
    }

    public String toString() {
        return Integer.toString(thing.i);
    }

    class FooInner{
        int i = 0;
    }


    public static void main(String[] args) {

        Foo foo = new Foo();

        System.out.println(foo); //Prints 0 

        FooInner thing = foo.getThing();
        thing.i = 10;

        System.out.println(foo); //Prints 10

    }
}

is the original private member within foo mutated?

不,因为您正在为 changeThing 中的变量 thing 分配一些新内容,而不是改变对象。如果您确实改变对象,改变也会反映在私有成员中。

注意getThing return Foo.thing引用的原始对象,不是它的副本。

由于在您的代码中,thing 属于 Object 类型,因此很难看到此行为。我将使用可变 class Baz 来演示:

public class Baz {
    public int x = 0;
}

public class Foo {
    private Baz thing;

    public Foo() { thing = new Baz(); }

    public Baz getThing() {
        return this.thing;
    }
}

public class Bar {
    public Bar() { ... }

    public Object makeNewThing() { ... }

    public void changeThing() {
        Foo foo = new Foo();
        Baz thing = foo.getThing();
        thing.x = 10;
        System.out.println(foo.thing); // this will print 10, not 0
    }
}

因此,为避免对 Foo.thing 进行任何修改,您可以:

  • 手动创建 thing 的副本并 return 它(Java 不会自动为您复制!)或者,
  • 使 thing 的类型不可变

查看评论:

public class Foo {
    private Object thing;

    //constructor to create an Foo-Object-Instance
    public Foo() { ... }

    //method to return a characteristic of a Foo-Object, 
    //whereas this characteristic is an object, not a primitive data type
    public Object getThing() {
        return this.thing;
    }
}

public class Bar {

    //constructor to create an Bar-Object-Instance
    public Bar() { ... }

    //returns an object and does whatever it's supposed to do within the { ... }
    //I wonder how's object connected to bar?
    public Object makeNewThing() { ... }

    public void changeThing() {
        //is Foo a subtype of Bar?

        //creating a Foo-Class-Instance (object)
        //that contains a variable Object (which is not the data as it would be with
        //primitive data types, but a reference to the data)
        Foo foo = new Foo();

        //and with "foo.getThing()" you get the reference ("address") 
        //of the Object foo's characteristic "thing" (which is an object 
        //as well, so you copy the address to the data) and add it to the 
        //new "Object thing", which
        //you have declared on the left side of the =

        //so you have two object variables pointing/with reference to the same data
        Object thing = foo.getThing();
        //when you use makeAnewThing - whatever stands in there - to change the 
        //object ("thing") variables data, then the data of the object will 
        //be changed if so stated in the { } and
        //hence basically the thing-object (or "variable") 
        //within the foo-object as well, 
        //because both variable names are pointing to the same data

        thing = makeThing();
    }
}

可能会造成混淆,因为您将两者都命名为 "thing",我。 e.在 foo-object 外声明的对象 thing 和在 foo-class.

内声明的对象变量 "thing"

重要的是对象和原始数据类型之间的区别,而对象变量或名称如 "String objectname" 或 "Object foo" 包含对数据的引用:

//declare an object named abs, which does not point to data
Object abc;
//declare an object named def and (right side of =) initiate it with data or variable or whatever the constructor says what's to be done
Object def = new Object();
//copy the reference ("address" of def-Object) to abc
abc = def;
//now we have one data thingi with two references to it, i. e. abc and def

如果您现在对 abc 添加更改,那么当在方法中声明时,这些更改将被添加到 abc 指向的数据中。如果您随后使用 def.getData() 之类的东西,将返回更改后的数据,因为 abc 和 def 都指向相同的数据。

首先,你应该了解引用类型的概念...

考虑以下代码: Foo f = new Foo();

事实上,这是两个订单

1, new foo() => 它在称为堆的内存部分创建一个 foo,它是你真正的 var 或内容

2, Foo f => 上面的var(content)地址放在f中。所以 f 是对内容的引用。

在您的代码中,当您 return this.thing 时,实际上,您 return 一个对象的引用或地址。

当你写的时候:

foo.getThing() return Foo class 中的东西,它是一个对象的引用或指针,然后

对象东西=foo.getThing();

将 Foo 的地址放在另一个名为 thing 的引用中。 这意味着它们都指向相同的内容...