如何制作 ArrayList 的单独副本? [复制]

Posted

技术标签:

【中文标题】如何制作 ArrayList 的单独副本? [复制]【英文标题】:How to make a separated copy of an ArrayList? [duplicate] 【发布时间】:2010-11-22 18:01:17 【问题描述】:

可能重复: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 的单独副本/克隆?

谢谢

【问题讨论】:

可能重复:***.com/questions/715650/… 正如 Zed 提到的那样。 我将其作为副本关闭,但不应将其删除。不是每个人都会知道使用原始使用的技术上更正确的“克隆”术语进行搜索。 【参考方案1】:

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

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

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() 形成对比,后者执行Listshallow copy。在这种情况下,浅拷贝会创建一个新的 List 实例,但包含对原始对象的引用。

【讨论】:

我认为如果您了解克隆列表与克隆列表中每个对象之间的区别,答案可能会更有帮助。但是,即使没有解释,答案也确实理解这一点,因此 +1 以补偿反对票。 错误:克隆在 java.lang.object 中具有“受保护”访问权限。 代码 sn-p 是基于 clone() 已在 Foo 类中被覆盖为公共的假设。【参考方案2】:

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

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

ArrayList copiedInvoice = new ArrayList(originalInvoice);

【讨论】:

【参考方案3】:

我认为我可以修改copyInvoice 中的项目,它不会影响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;

在这种情况下,一个和两个对相同的共享“某物”具有相同的引用变量,并且更改其中一个的值会影响另一个。

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

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

【讨论】:

你说你分享你的第一堂课不会有问题:东西。但是,Date 是一个对象,更重要的是它是可变的,因此需要复制。 :P 不可变对象的错误选择.. 我为可变对象考虑了日期。谢谢亚当斯基【参考方案4】:

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

【讨论】:

以上是关于如何制作 ArrayList 的单独副本? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

如何制作Java ArrayList的深层副本[重复]

如何在我的 github 上制作分支的本地副本? [复制]

如何制作对象的深层副本?

如何制作一个快速的类对象数组的深层副本

如何制作 Core Data 对象图的精确副本?

如何在 iOS 中制作 OpenGL ES 帧缓冲区的副本?