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

Fif*_*a89 3 java

如果我有课:

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

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

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

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

我不能这样做:

MyType instance1 = new MyType(someData, false);  
MyType instance2 = new MyType(instance1.getData(), instance1.getFlag());
Run Code Online (Sandbox Code Playgroud)

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

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

MyType someVar = new MyType(someList, false);

// Now, I want a copy of someVar, not another variable pointing to the same reference.
Run Code Online (Sandbox Code Playgroud)

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

Jas*_*ols 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);  
   }
}
Run Code Online (Sandbox Code Playgroud)

复制构造函数很常见,可以在许多集合实现中找到.出于清晰的原因,我更喜欢他们而不是实现Cloneable.同样值得注意的是,即使是强大的Joshua Bloch在Effective Java(第二版第61页)中也表示复制构造函数比Cloneable/clone有许多优点.

  • 他们不依赖于易于冒险的语言外对象创建机制
  • 他们并不要求无法强制遵守精简文件的惯例
  • 它们与正确使用最终字段不冲突
  • 它们不会抛出不必要的已检查异常
  • 他们不需要演员阵容.

如果你没有他的书,那就去吧!


Boz*_*zho 6

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

List newData = new ArrayList(data)
Run Code Online (Sandbox Code Playgroud)

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


如果您需要克隆更大的对象图,则分两步:

  1. 让你的类实现Serializable接口
  2. 使用apache commons-lang SerializationUtils.clone(yourObject)

它使用java中的序列化机制进行深层复制.

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