在阅读了多篇关于如何破坏ArrayList类中的clone()的帖子(here's one)后,我想知道没有人重新实现它,这样就不会破坏人们可以更舒服的地方方法。
我有什么东西在这里缺失的原因是为什么没有人重新实施它以免它被破坏?
答案 0 :(得分:4)
clone()
本身没有被破坏:它根据clone()
方法的规范很好地实现。有问题的地方就是这个规范本身。正如在链接问题中已经讨论过的那样,有几个缺点,即必须进行未经检查的演员表,如果你的ArrayList
被覆盖则会出现潜在的问题以及必须知道输入{{1}实际上是List
。任何需要ArrayList
的代码的良好做法是接受任何ArrayList
(甚至List
)实现:这样您的代码就变得更加灵活。
正如已经指出的那样,有一个更好的选择:使用
Collection
它是通用的:它适用于任何源集合,结果将是ArrayList<Type> copy = new ArrayList<>(source);
(非派生类)。你不应该担心性能。根据实施情况,它大致相同。请参阅clone()方法代码:
ArrayList
因此它产生浅拷贝(快速操作的常数复杂性,因为浅的大小是恒定的和小的),然后进行单个数组复制并替换mod计数。让我们检查一下构造函数:
public Object clone() {
try {
@SuppressWarnings("unchecked")
ArrayList<E> v = (ArrayList<E>) super.clone();
v.elementData = Arrays.copyOf(elementData, size);
v.modCount = 0;
return v;
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
throw new InternalError();
}
}
它调用原始集合的public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
size = elementData.length;
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
}
,将其结果用作自身的内部数组并更新大小。仅当原始集合错误地从toArray
方法返回类型化数组时,它才会复制数组。如果输入集合也是toArray
会发生什么?查看ArrayList
:
ArrayList.toArray
请参阅,它与public Object[] toArray() {
return Arrays.copyOf(elementData, size);
}
方法中的操作完全相同。因此,在这两种情况下(克隆和复制构造函数),您都有单clone()
次调用和小的常量开销。