如何制作ArrayList的分离副本?

时间:2009-08-25 18:59:13

标签: java arraylist clone

  

可能重复:
  Java: how to clone ArrayList but also clone its items?

我有一个示例程序,如下所示:

ArrayList<Invoice> orginalInvoice = new ArrayList<Invoice>();

//add some items into it here

ArrayList<Invoice> copiedInvoice = new ArrayList<Invoice>();

copiedInvoice.addAll(orginalInvoice);


我以为我可以修改copiedInvoice内的项目,但不会影响originalInoice中的这些项目。但是我错了。

如何对ArrayList

进行单独的复制/克隆

由于

4 个答案:

答案 0 :(得分:39)

是的,这是正确的 - 你需要实现clone()(或其他合适的机制来复制你的对象,因为clone()被许多程序员视为“破坏”。您的clone()方法应该对对象中的所有可变字段执行深层复制。这样,对克隆对象的修改不会影响原始对象。

在您的示例代码中,您创建了第二个ArrayList并使用对相同对象的引用填充它,这就是为什么{{1}可以看到对象的更改的原因}秒。使用克隆方法,您的代码将如下所示:

List

编辑:为了澄清,上述代码正在执行原始List<Foo> originalList = ...; // Create new List with same capacity as original (for efficiency). List<Foo> copy = new ArrayList<Foo>(originalList.size()); for (Foo foo: originalList) { copy.add((Foo)foo.clone()); } 深层复制,其中新List包含对副本的引用原始对象。这与调用List形成对比,ArrayList.clone()执行shallow copy的{​​{1}}。在此上下文中,浅表副本会创建一个新的List实例,但包含对原始对象的引用。

答案 1 :(得分:17)

如果要将可变对象存储到ArrayList中,则需要在复制ArrayList时复制每个对象。否则,新的ArrayList仍将保留原始引用。

但是如果你要存储不可变对象,可以使用它:

ArrayList copiedInvoice = new ArrayList(originalInvoice);

答案 2 :(得分:2)

  

我以为我可以修改copiedInvoice中的项目,它不会影响originalInoice中的这些主题。

这是因为复制的是引用变量而不是它自己的对象。

因此,您最终得到两个指向同一对象的“引用”。

如果您需要复制整个对象,则可能需要克隆它。

但如果您没有克隆对象内部属性(如果它们碰巧是其他对象),则可能会遇到问题。

例如,以下类定义不会给您带来任何问题。

  public class Something {
       private int x;
       private int y;
       private String stringObject;
   }

如果你创建了它的副本,你将复制其属性的当前值,就是这样。

但是如果你的类里面有另一个对象,你也可以考虑克隆它。

 class OtherSomething {
        Something something;
       private int x;
 }

如果您执行以下操作:

 Something shared = new Something();

 OtherSomething one = new OtherSomething();

 OtherSomething two = new OtherSomething();

 one.something = shared;
 two.something = shared;

在这种情况下,一个和两个具有相同的共享“某物”的相同参考变量,而改变一个中的值会影响另一个。

这就是使用不可变对象更简单/更好/更容易的原因。

如果需要更改不可变对象的值,只需创建一个具有正确值的新值即可。

答案 3 :(得分:-1)

看看ByteArrayOutputStream和ByteArrayInputStream。如果所有类都实现了Serializable,那么您可以使用上面提到的类进行复制。