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

public Object[] toArray() { // Estimate size of array; be prepared to see more or fewer elements Object[] r = new Object[size()]; Iterator 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. 如果这是真的,在调用方法时,什么情况可以使大小改变?

好吧,方法的javadoc就是这样:

  /** * {@inheritDoc} * * 

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. * *

This method is equivalent to: * *

 {@code * List list = new ArrayList(size()); * for (E e : this) * list.add(e); * return list.toArray(); * }

*/

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

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

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

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

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

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

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

因此,回答这个问题:

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

  2. 如上所述,自收集合同以来,不同的可能性非常宽松。 multithreading,大小()和其他的近似结果。

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

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

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

    Collection thingsACatholicCanEat; //如果周五不应该包括肉类