【问题标题】:If clone( ) for ArrayList is broken why can't they fix it?如果 ArrayList 的 clone() 坏了,为什么他们不能修复它?
【发布时间】:2015-06-30 01:50:53
【问题描述】:

在阅读了多篇关于 ArrayList 类中的 clone( ) 如何被破坏的帖子 (here's one) 之后,我想知道没有人重新实现它以便它不会被破坏,人们可以更舒适地使用该方法.

我在这里遗漏了什么是因为没有人重新实现它以使其不被破坏吗?

【问题讨论】:

  • 我认为这不是关于实现,而是更多关于接口本身。如果不破坏任何使用它的代码,就无法修复损坏的界面。
  • new ArrayList<>(old) 也没有那么不好。
  • @DavidEhrmann 在许多克隆帖子中没有人推荐这一点也很有趣

标签: java arraylist clone


【解决方案1】:

clone() 本身并没有损坏:它根据clone() 方法的规范很好地实现了。有问题的地方是这个规范本身。正如在链接问题中已经讨论过的那样,有几个缺点,即必须进行未经检查的演员表,如果您的 ArrayList 被覆盖会出现的潜在问题以及需要知道输入 List 实际上是ArrayList。对于需要 ArrayList 的任何代码,一个好的做法是接受任何 List(甚至是 Collection)实现:这样您的代码就会变得更加灵活。

正如已经指出的,有一个更好的选择:使用

ArrayList<Type> copy = new ArrayList<>(source);

它是通用的:它适用于任何源集合,结果将完全是ArrayList(不是派生类)。你不应该担心性能。根据实现,它大致相同。查看clone()方法代码:

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();
    }
}

所以它做了一个浅层副本(由于浅层大小是恒定且小的,因此快速操作的复杂性),然后制作单个数组副本并替换 mod 计数。让我们检查一下构造函数:

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()方法中的操作完全一样。因此,在这两种情况下(克隆和复制构造函数),您只有一个 Arrays.copyOf(elementData, size) 调用和较小的常量开销。

【讨论】:

    猜你喜欢
    • 2011-08-11
    • 2021-01-28
    • 2013-06-07
    • 2012-05-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多