在Java中按值复制对象列表

时间:2012-05-08 09:16:19

标签: java collections

我有一个类,它的构造函数中包含一个对象列表List<Object>。 每次列表都可以来自不同类型的元素。这是通用的,我不知道他们的班级类型是什么。

在让用户更改其值之前,我想保存自己的该列表的副本。但由于副本是通过引用完成的,因此两个列表(原始和副本)都在更改......

如何按值复制列表?

谢谢, Devora

7 个答案:

答案 0 :(得分:2)

你的问题不明确。

  • 如果你想要一个浅拷贝(即列表的副本将包含对原始列表中对象的引用,那么clone方法将完成这项工作,复制构造函数也是如此。 List实施班。

  • 如果您需要深层复制(即包含原始对象副本的列表副本),那么最好的办法是创建一个新列表并使用原始列表元素的克隆填充它。然而,有一个问题。默认情况下不提供clone方法。许多常见的实用程序类都是可复制的,自定义类不是......除非你已经实现了它。如果列表包含任何非可克隆对象,则在运行时将获得异常。

clone还有其他深层复制替代方案,但就像克隆一样,它们不适用于所有类。实际上,如果您的解决方案必须是通用的,那就是问题的关键。

答案 1 :(得分:1)

您需要创建一个新的List,然后将原始列表中每个元素的克隆添加到其中。

List<Object> copy = new ArrayList<Object>(inputList.size());
for (Object item : inputList) {
   copy.add(item.clone());
}

显然,您需要检查列表中的对象是Cloneable,否则将无法正确复制。

答案 2 :(得分:0)

遍历传递的列表并查看其内容以创建新的List,然后可以在不更改原始List的情况下使用它。

private List<Object> clone;
public Foo(List<Object> original)
{
  this.clone = new ArrayList<Object>(list.size());
  for(Object item: original)
  { 
   clone.add(item.clone());
  }
}

答案 3 :(得分:0)

答案 4 :(得分:0)

如果您的对象不包含其他对象的任何其他引用,则可以使用Object.clone(),但如果不是,则需要进行深度克隆。

答案 5 :(得分:0)

在这些类型的情况下,有三种常见的解决方案:

(1)如果您知道各个元素具有按预期工作的 clone()方法,请创建一个新数组并使用每个相应元素的clone()填充它。根据经验,JDK中的“基本”对象,如字符串,数字表示等应该没问题。 clone()的一个缺点是它有点像'松散的大炮':如果某个特定类的方法已被覆盖,并且可能会获得哪些引用,那么你不知道'克隆'究竟有多深。是否重复使用。它还有一个特殊的危险,即依赖于构造函数中的逻辑的可克隆对象的子类可能无法正常工作。但正如我所说,简单的JDK对象应该没问题。

(2)序列化包含ByteArrayOutputStream的ObjectOutputStream的列表。然后获取生成的字节数组,并在其周围包装一个ByteArrayInputStream和ObjectInputStream,并从中读入一个新的深度列表副本。

(3)在理想的世界中,创建一个新列表,用相关对象的明确创建“副本”填充它。如果编码不太麻烦,这是理想的解决方案,因为你“知道实际发生了什么”:对于意外重新引用而不是重新创建的对象,没有隐藏的意外,例如, clone()方法没有按预期工作。

由于您有一个简单的容器对象(数组列表),其结构可以轻松地重新创建,因此(2)可能过度。它可以很方便地重新创建更复杂的结构。

Re(1),您应该特别怀疑从第三方库中克隆对象,其中对象不是专门针对clone()设计的。问题是人们很容易将JDK(可克隆)类或者令牌clone()方法子类化而不实际详细考虑它 - 根据我的经验,clone()有一些微妙之处,很多开发人员都没有意识到(例如,构造函数不会被新对象调用),这可能导致意外问题。因此,如果你实际上看不到可靠的源代码以确保clone()是安全的,我会避免它。

答案 6 :(得分:-2)

如果你有:

List<Object> objects

您可以按以下方式复制此列表:

List<Object> newObjects = new ArrayList<Object>(objects);

[更新:添加ArrayList的实际实现以证明它复制了新对象]

请参阅ArrayList的实际实现,它复制对象 - 不包含对同一对象的引用。

public ArrayList(Collection<? extends E> c) { elementData = c.toArray(); size = elementData.length; if (elementData.getClass() != Object[].class) elementData = Arrays.copyOf(elementData, size, Object[].class); }

public Object[] toArray() { return Arrays.copyOf(elementData, size); }