2

我不完全理解 Java 何时传递副本/值以及何时传递“引用”(指针)。

我正在尝试分配我拥有的静态对象的副本,但我不确定如何去做。

我有这个:

static ArrayList<MyObject> myObjects;

我想获取 myObjects 的副本,以便我可以在不影响原始值的情况下使用这些值。当我像这样使用 getter 时,它是否传递了引用或副本/值:

public static ArrayList<MyObject> getMyObject()
{
    return ThisClass.myObjects;
}

那返回什么?如果它是参考,我怎样才能获得副本?

我见过这些:

如何在 Java 中复制对象?

Java:getter 方法与公共实例变量:性能和内存

Java 是“按引用传递”还是“按值传递”?

如何进行 Java 赋值以指向对象而不是复制?

但我仍然不太明白我会得到什么。

4

4 回答 4

5

只要它不是原始类型(aka long, int, short, etc 或原始包装之一Long, Integer, Short.

要获取副本,您需要复制数据、使用复制构造函数或使用clone将创建具有适当值的新对象的方法。

带有列表的复制构造函数的示例,默认情况下这是一个“浅拷贝”,这意味着里面的对象是相同的。

List<MyObject> myNewCopiedList = new ArrayList<MyObject>(oldList);

对于“深层副本”,这意味着可以在不影响原始对象的情况下对内部对象进行变异,您需要创建一个新列表,然后添加对象的副本/克隆并添加。

例如,假设 MyObject 具有复制构造函数或clone方法。

List<MyObject> myNewCopiedList = new ArrayList<MyObject>();
for (MyObject myo : oldList){
    myNewCopiedList.add(new MyObject(myo)); // if there is a copy constructor
    myNewCopiedList.add(myo.clone()); // if there is clone method
}
于 2013-06-04T16:30:14.363 回答
2

这样想吧。Java 总是按值传递。

对于原语,它是按值(实际值)传递的。对于对象,它是通过引用值传递的。

public int square(int a) { //The parameter a is copy of actual int itself.
//So now there are 2 ints
a=a*a;   //Only local copy a is actually modified. 
         //The integer variable passed(in caller function) is not modified.
return a;
}

如果调用 doSomething(d) where dis an object,则指向该对象的引用副本分配给参数a ,但只有一个对象。

public void doSomething(Object a) { 
// Here the parameter is a reference which points to an 
//  object, not the object itself 
a.doMore(); //But doMore() does things using a different ref but on the same object.
            //The object can be modified!

Object b = new Object();  
a = b;   //Object referenced by passed parameter does not change but 
         //copy of reference now points to different object.
         // Now there is no reference of original object passed in this method.
}
于 2013-06-04T17:21:30.883 回答
1

为了正确地复制对象,必须知道哪些非原始字段封装

  • 对象状态的可变方面,但不是其身份

  • 对象的身份和其他不可变方面,但没有可变方面。

  • 预计永远不会暴露于任何可能改变它们的代码(而不是身份)的对象方面

  • 对象状态的可变方面,以及它的身份

基于字段封装的内容,正确的副本Foo

  • 如果其中一个Foo封装了可变状态的字段,则副本中的相应字段Foo应包含对具有相同状态的不同对象的引用。

  • 如果一个字段封装了对象身份,则副本中的该字段必须包含对与中相同的对象的引用Foo——而不是副本

  • 如果一个字段只封装了除 identity 之外的不可变方面,那么一个副本Foo可以包含对与 in 相同的对象的引用Foo,或者任何具有相同不可变状态的对象,以方便起见。

  • 如果一个字段同时封装了可变状态和标识,因为前两个需求会发生冲突,所以无法单独复制对象。

在某些情况下,可以复制一组可变对象,这些对象使用相互引用来封装状态和身份。这种复制必须在整个片场上进行;对于集合中的每个对象,原始对象中的任何字段既封装了原始集合中另一个对象的可变状态和身份,也必须在副本中引用复制集中的相应对象。

于 2013-06-04T16:57:43.090 回答
1

从技术上讲,Java 始终是按值传递的。但是,对于初学者的想法,这样考虑会更容易:

如果它是原始类型,则它是按值传递的。

如果它是一个object,它是通过引用传递的。

因此,在您的示例中,您将返回staticThisClass. 我说这在技术上是按值传递的原因是因为您的变量myObjects实际上存储了ArrayList<MyObject>您声明的内存地址,并且传递的是 this。

于 2013-06-04T16:30:24.237 回答