【问题标题】:ArrayList shallow copy iterate or clone()ArrayList 浅拷贝迭代或 clone()
【发布时间】:2010-04-07 13:54:09
【问题描述】:

我需要一个 java ArrayList 的浅拷贝,我应该使用 clone() 还是遍历原始列表并将元素复制到新的 arrayList 中,这样更快?

【问题讨论】:

  • 在输入问题的过程中,您应该已经看到弹出了相关问题的列表(与您在本页右下角看到的列表相同)。你偷看他们吗?为什么这些答案还不够?请详细说明。
  • 我确实浏览了弹出窗口。 ArrayList iterator vs clone() 与性能无关。

标签: java


【解决方案1】:

无需迭代:

List original = ...
List shallowCopy = new ArrayList(original);

http://java.sun.com/javase/6/docs/api/java/util/ArrayList.html#ArrayList%28java.util.Collection%29

【讨论】:

  • 但是这不是线程安全的。 (在这里结束,因为我得到 ConcurrentModificationException 这样做)
【解决方案2】:

使用clone(),或使用复制构造函数。

复制构造函数将传递的集合额外转换为数组,而clone()方法直接使用内部数组。

请记住,clone() 返回 Object,因此您必须转换为 List

【讨论】:

  • 正是我查看了 java.util.ArrayList 源代码,发现 clone() 使用了 Array.copyof,这比循环遍历原始 ArrayList 效率高得多。 public Object clone() { try { @SuppressWarnings("unchecked") ArrayList v = (ArrayList) super.clone(); v.elementData = Arrays.copyOf(elementData, size); v.modCount = 0;返回 v; } catch (CloneNotSupportedException e) { // 这不应该发生,因为我们是 Cloneable throw new InternalError(); } }
  • 我不会太担心效率。使用 clone() 很痛苦;只需按照建议使用转换构造函数。
  • @Kevin Bourrillion 为什么你认为使用clone() 很痛苦?实现clone() 很痛苦,不使用它。
  • 通常情况下,你永远不想写很多依赖于实现类的代码,ArrayList;普遍认可的最佳实践是限制您对接口类型的依赖,例如List。但是如果不知道具体的实现类型(ArrayListLinkedList 等),您就无法克隆 List,您可以先将其向下转换!然后,一旦你得到结果,它就是一个Object,所以你也必须投射它!最重要的是,一些实现不会费心吞下自己的CloneNotSupportedExceptions。最糟糕的是,因为这更加痛苦(续)
  • ...与简单的转换构造函数相比,许多库根本不会费心去玩克隆游戏。社区在很大程度上受够了这一切。我建议你完全忘记克隆的概念甚至存在,除了偶尔克隆一个数组,这很方便。坦率地说,情况是如此糟糕,以至于听到有人声称使用它并不痛苦,我感到很震惊!
【解决方案3】:

您可以使用copy constructor,而不是手动迭代。

至于那和使用clone()的速度差异:

  1. 没关系
  2. 很可能没有
  3. 针对您的特定系统配置和用例进行基准测试

【讨论】:

  • @Michael..谢谢。我检查了复制构造函数的代码。正如 Bozho 提到的,它有额外的步骤来返回复制内部数组结构。 public ArrayList(Collection extends E> c) { elementData = c.toArray();大小 = elementData.length; if (elementData.getClass() != Object[].class) elementData = Arrays.copyOf(elementData, size, Object[].class); }
  • 我喜欢通用的“我应该优化吗?”思维模式
【解决方案4】:

问题是浅拷贝而不是深拷贝。将引用从一个数组列表引用直接复制到另一个也可以正常工作。深拷贝包括复制数组列表中的单个元素。

ArrayList<Integer> list=new ArrayList<Integer>();
list.add(3);
ArrayList<Integer> list1=list; //shallow copy...

这有什么问题吗??

【讨论】:

  • 这是错误的。所有这一切都会使内存中有两个指向一个物理ArrayList 对象的指针。将Integer 添加到一个列表会使Integer 也出现在另一个列表中。那不是我们想要的。浅拷贝使底层对象共享相同的内存空间,但列表具有单独的内存空间。因此,如果您修改一个Integer,它将在两个列表中进行修改。但是,如果您将Integer 添加到一个列表中,它将不会出现在另一个列表中。深拷贝不会反映对其他列表中任何内容的任何更改。
猜你喜欢
  • 1970-01-01
  • 2011-07-13
  • 2012-04-12
  • 1970-01-01
  • 1970-01-01
  • 2012-07-06
  • 2015-01-13
  • 2011-09-05
相关资源
最近更新 更多