获取对象的副本

时间:2013-06-04 16:28:14

标签: java pointers reference getter

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

我正在尝试分配我拥有的静态对象的副本,但我不确定该怎么做。

我有这个:

static ArrayList<MyObject> myObjects;

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

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

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

我见过这些:

How do I copy an object in Java?

Java: getter method vs. public instance variable: performance and memory

Is Java "pass-by-reference" or "pass-by-value"?

How can Java assignment be made to point to an object instead of making a copy?

但我仍然不太清楚我会得到什么。

4 个答案:

答案 0 :(得分:5)

只要Java不是基本类型(aka longintshort等或原始包装器{{}之一,它将始终返回引用而不是副本。 1}},LongInteger

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

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

clone

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

示例,假设MyObject具有复制构造函数或List<MyObject> myNewCopiedList = new ArrayList<MyObject>(oldList); 方法。

clone

答案 1 :(得分: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)其中d是一个对象,则指向此对象的引用副本将分配给参数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.
}

答案 2 :(得分:1)

从技术上讲,Java始终是按值传递的。然而,对于初学者的思考,以这种方式思考它更容易:

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

如果它是对象,则它是传递引用。

因此,在您的示例中,您将返回对static中相同ThisClass对象的引用。我说这是技术上按值传递的原因是因为你的变量myObjects实际上存储了你声明的ArrayList<MyObject>的内存地址,而且这是传递的。

答案 3 :(得分:1)

为了正确制作一个对象的副本,必须知道哪些非原始字段封装

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

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

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

  • 对象状态的可变方面及其身份

根据字段封装的内容,Foo

的正确副本
  • 如果Foo的某个字段封装了可变状态,则Foo副本中的相应字段应该保存对具有相同状态的其他对象的引用。

  • 如果某个字段封装了对象标识,则该副本中的该字段必须包含与Foo - 中的相同对象的引用,而不是副本

  • 如果字段仅封装除标识以外的不可变方面,则Foo的副本可以保存对Foo中同一对象的引用,或者任何具有相同不可变状态的对象,方便。

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

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