在AbstractCollection的toArray方法的实现中,代码的用法是什么

时间:2011-12-06 14:37:29

标签: java collections

public Object[] toArray() {
    // Estimate size of array; be prepared to see more or fewer elements
    Object[] r = new Object[size()];
    Iterator<E> it = iterator();
    for (int i = 0; i < r.length; i++) {
        if (! it.hasNext()) // fewer elements than expected
            return Arrays.copyOf(r, i);
        r[i] = it.next();
    }
    return it.hasNext() ? finishToArray(r, it) : r;
}

这是AbstractCollection.toArray方法的实施代码。

if (! it.hasNext()) // fewer elements than expected
    return Arrays.copyOf(r, i);

我不明白上面代码的用法。我怀疑代码用于避免在调用方法时更改大小。所以我有两个问题:

  1. 我怀疑是对还是错?如果这是错的,这段代码的用法是什么?
  2. 如果确实如此,在调用方法时,什么情况可以改变大小?

5 个答案:

答案 0 :(得分:6)

嗯,方法的javadoc就是这样:

 /**
     * {@inheritDoc}
     *
     * <p>This implementation returns an array containing all the elements
     * returned by this collection's iterator, in the same order, stored in
     * consecutive elements of the array, starting with index {@code 0}.
     * The length of the returned array is equal to the number of elements
     * returned by the iterator, even if the size of this collection changes
     * during iteration, as might happen if the collection permits
     * concurrent modification during iteration.  The {@code size} method is
     * called only as an optimization hint; the correct result is returned
     * even if the iterator returns a different number of elements.
     *
     * <p>This method is equivalent to:
     *
     *  <pre> {@code
     * List<E> list = new ArrayList<E>(size());
     * for (E e : this)
     *     list.add(e);
     * return list.toArray();
     * }</pre>
     */

我发现有两件有趣的事情要提到:

  1. 是的,你是对的,就像javadoc sais一样,即使Collection同时被修改,这个方法也准备正确返回。这就是为什么初始尺寸只是一个提示。迭代器的使用也确保避免“并发修改”异常。

  2. 很容易想象一个多线程情况,其中一个线程在Collection中添加/删除元素,而另一个线程在其上调用“toArray”方法。在这种情况下,如果Collection不是线程安全的(如通过Collections.synchronizedCollection(...)方法获得,或者通过手动创建同步访问代码),您将进入一个被修改的状态,并在同一时间进行编译时间。

答案 1 :(得分:3)

我只想提一下,根据javadoc,方法size()可以返回最大的Integer.MAX_VALUE。但是如果你的收藏品有更多的元素,你将无法获得合适的尺寸。

答案 2 :(得分:0)

你是对的,数组是用size()初始化的,所以如果在填充数组时删除了任何元素,你可以从这个检查中受益。

默认情况下,集合不是线程安全的,因此在迭代进行时,另一个线程可以调用remove(): - )

答案 3 :(得分:0)

虽然通常保证(例如对于所有java.util。*集合类)集合在迭代时不会更改(否则会抛出ConcurrentModificationException),但并不能保证所有集合都能保证。因此,当一个线程调用toArray()时,另一个线程可以添加或删除元素,从而改变集合的大小,从而改变结果数组。或者,某些实现可能只返回大致的大小。

因此,回答这个问题:

  1. 这两行检查是否在达到预期大小(定义r.length的size()调用的结果)之前到达了集合的结尾。如果是这种情况,将生成具有适当大小的数组r的副本。请记住,无法调整阵列大小。

  2. 如上所述,自收集合约以来,不同的可能性相当宽松。多线程,大小()和其他的近似结果。

答案 4 :(得分:0)

Andrei是主要答案。 corsair提出了一个关于Integer.MAX_VALUE的优秀观点。

为了完整性,我将添加toArray方法应该适用于任何Collection,包括:

  1. 带有错误尺寸方法的数组;
  2. 动态数组 - Collection的内容可能会根据其他线程(并发),时间或随机数而变化。伪代码中的一个例子

    收藏&lt;食物&gt; thingsACatholicCanEat; //如果它是星期五不应该包括肉