如何创建我在Java中创建的数据类型的副本?

时间:2010-02-17 18:52:02

标签: java

如果我有课:

public class MyType  
{  
    private List<Integer> data;  
    private boolean someFlag;

    public MyType(List<Integer> myData, boolean myFlag)
    {
        this.data = myData;
        this.myFlag = someFlag; 
    } 
}

现在,如果我创建一个MyType实例,我该如何对其进行深层复制呢?我不希望新对象指向旧引用,而是一个全新的实例。

这是我应该实现Cloneable接口的情况,还是用于浅拷贝?

我不能这样做:

MyType instance1 = new MyType(someData, false);  
MyType instance2 = new MyType(instance1.getData(), instance1.getFlag());

我担心MyType的新实例指向其“data”变量的相同引用。所以我需要完全复制它。

所以,如果我有一个现有的对象:

MyType someVar = new MyType(someList, false);

// Now, I want a copy of someVar, not another variable pointing to the same reference.

有人能指出我正确的方向吗?

5 个答案:

答案 0 :(得分:7)

首先:您的代码示例有一些命名问题:它是 myFlag 还是 someFlag

许多开发人员将弃用Cloneable,只需在需要深层副本时为类创建一个复制构造函数:

public class MyType {

   private boolean myFlag;
   private List<Integer> myList;

   public MyType(MyType myInstance) {
      myFlag = myInstance.myFlag;
      myList = new ArrayList<Integer>(myInstance.myList);  
   }
}

复制构造函数很常见,可以在许多集合实现中找到。出于清晰的原因,我更喜欢他们而不是实现Cloneable。同样值得注意的是,即使是强大的约书亚布洛赫在Effective Java(第二版第61页)中也说复制构造函数比克隆/克隆有许多优势。

  • 他们不依赖于风险 语外对象创造 机制
  • 他们不要求无法执行 坚持细记 约定
  • 他们与正确的人没有冲突 使用最终字段
  • 他们不会抛出不必要的检查 例外
  • 他们不需要演员阵容。

如果你没有他的书,得到它

答案 1 :(得分:6)

您可以使对象图中的所有类实现Cloneable并提供手动克隆。因为在你的情况下它只是一个列表(即一个非常小的对象图),你最好使用copy-constructor:

List newData = new ArrayList(data)

但请记住,在这种情况下,列表的内容仍然是相同的对象,因此它不会是真正的深层副本。在你的情况下,这些是Integer s,所以没什么大不了的。但如果你改变它,要小心。


如果你需要克隆更大的对象图,那么分两步:

  1. 让您的班级实现Serializable界面
  2. 使用apache commons-lang SerializationUtils.clone(yourObject)
  3. 它使用java中的序列化机制进行深层复制。

    或者,您可以使用this library - 它不需要Serializable界面,并使用反射制作深层副本。

答案 2 :(得分:1)

您应该实施Cloneable定义“您的类型的副本”的确切含义。有时需要一个包含字段的类型,其内容在多个副本中保持相同(==在所有复制的实例中引用同一个对象)

您必须自己照顾所有字段实际上都复制到新实例。原始数据类型(如int,long等)在直接存储时被复制,它们从不包含引用。

如果您有对象引用的字段,那么您需要找到一种机制来创建每种类型的副本。

通常,在调用.clone()后,您确实有一个浅表副本。如果(且仅当)您的类中使用的所有类型都正确地实现了Cloneable,那么您将获得完全递归的深层复制。

根据JavaDoc (Object.clone()) Clonable表示以下内容:

x.clone() != x && x.clone().getClass() == x.getClass() && x.clone().equals(x)

请记住,这是一般的意图,这是不是强制性合同

答案 3 :(得分:0)

你的类MyType必须实现Cloneable。然后你可以调用someVar.clone()

答案 4 :(得分:-1)

实施ICloneable