在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);
我不明白上面代码的用法。 我怀疑代码用于避免在调用方法时更改大小。 所以我有两个问题:
- 我怀疑是对还是错? 如果这是错的,这段代码的用法是什么?
- 如果这是真的,在调用方法时,什么情况可以使大小改变?
好吧,方法的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 * Listlist = new ArrayList (size()); * for (E e : this) * list.add(e); * return list.toArray(); * } */
我发现这里有两件有趣的事情要提到:
是的,你是对的,就像javadoc sais一样,即使Collection在同一时间被修改,这个方法也准备好正确返回。 这就是为什么初始尺寸只是一个提示。 迭代器的使用还确保避免“并发修改”exception。
很容易想象一个multithreading情况,其中一个线程在Collection中添加/删除元素,而另一个线程在其上调用“toArray”方法。 在这种情况下,如果Collection不是线程安全的(如通过
Collections.synchronizedCollection(...)
方法获得,或者通过手动创建同步访问代码),您将进入一个被修改的状态和toArray-ed同时。
我只想提一下,根据javadoc ,方法size()
可以返回最大的Integer.MAX_VALUE。 但是如果你的系列有更多的元素,你就无法获得合适的尺寸。
你是对的,数组是用size()初始化的,所以如果在填充数组时删除了任何元素,你将从这个检查中受益。
默认情况下,集合不是线程安全的,因此另一个线程可以在迭代进行时调用remove():-)
虽然通常保证(例如对于所有java.util。*集合类)集合在迭代时不会更改(否则会抛出ConcurrentModificationException),但并不能保证所有集合都能保证。 因此,当一个线程调用toArray()时,另一个线程可以添加或删除元素,从而改变集合的大小,从而改变结果数组。 或者,某些实现可能仅返回大致的大小。
因此,回答这个问题:
-
这两行检查是否在达到预期大小(定义r.length的size()调用的结果)之前到达了集合的结尾。 如果是这种情况,将生成具有适当大小的数组r的副本。 请记住,无法调整arrays大小。
-
如上所述,自收集合同以来,不同的可能性非常宽松。 multithreading,大小()和其他的近似结果。
安德烈是主要答案。 corsair提出了一个关于Integer.MAX_VALUE的优秀观点。
为了完整性,我将添加toArray方法应该适用于任何Collection,包括:
- 具有错误大小方法的数组;
-
动态数组 – Collection的内容可能会根据其他线程(并发),时间或随机数而变化。 伪代码中的一个例子
Collection
thingsACatholicCanEat; //如果周五不应该包括肉类