AbstractCollection的toArray()分析

Posted on 2018-03-08 22:07  林浩开发小屋  阅读(249)  评论(0)    收藏  举报
 1     public Object[] toArray() {
 2         // Estimate size of array; be prepared to see more or fewer elements
 3         Object[] r = new Object[size()];
 4         Iterator<E> it = iterator();
 5         for (int i = 0; i < r.length; i++) {
 6             if (! it.hasNext()) // fewer elements than expected
 7                 return Arrays.copyOf(r, i);
 8             r[i] = it.next();
 9         }
10         return it.hasNext() ? finishToArray(r, it) : r;
  1. 先根据size()的大小生成一个数组,然后根据迭代器的hasNext来判断,当前迭代器后面还有没有值,并用i记录当前的已经存入的元素数量。
  2. 如果迭代器实际迭代的数量的大小比size小,则使用Arrays.copyOf来截断当前的数组,然后直接返回。
  3. 需要说明的是Arrays的静态方法是java针对数组来实现的一系列方法。其中copyOf将传入的数组复制到一个新的数组中,新的数组的大小由第二个参数来指定。
  4. 如果迭代器实际迭代的数量的大小比size大,则调用finishToArray来完成之后迭代器的实现。

 

 1     @SuppressWarnings("unchecked")
 2     private static <T> T[] finishToArray(T[] r, Iterator<?> it) {
 3         int i = r.length;
 4         while (it.hasNext()) {
 5             int cap = r.length;
 6             if (i == cap) {
 7                 int newCap = cap + (cap >> 1) + 1;
 8                 // overflow-conscious code
 9                 if (newCap - MAX_ARRAY_SIZE > 0)
10                     newCap = hugeCapacity(cap + 1);
11                 r = Arrays.copyOf(r, newCap);
12             }
13             r[i++] = (T)it.next();
14         }
15         // trim if overallocated
16         return (i == r.length) ? r : Arrays.copyOf(r, i);
17     }
  1. i表示当前的迭代的元素的数量,总的来说i每次进入循环体就增加一个.而另一个cap表示当前的数组的大小。
  2. 第一次进入i==cap,说明需要增大cap。这里增加的cap的一半并加1的大小,然后判断下新的数组的大小是否超过VM的最大界限,如果没有就将继续循环体。
  3. 每次进入循环体,先用cap确认下当前数组的长度。如果i还没有增长到cap相同的程度则只要将迭代器的下一个元素放入数组并将i加一就行
  4. 在返回的时候使用根据已经迭代的元素i来复制当前数组到一个新的数组中。
1     private static int hugeCapacity(int minCapacity) {
2         if (minCapacity < 0) // overflow
3             throw new OutOfMemoryError
4                 ("Required array size too large");
5         return (minCapacity > MAX_ARRAY_SIZE) ?
6             Integer.MAX_VALUE :
7             MAX_ARRAY_SIZE;
8     }
  1.  如果当前的cap最大值不可在继续增大,即cap+1为负值则抛出一个超出内存大小的异常。Integer.MAX_VALUE+1 <0
  2. 如果当前的值可以分配,则分配一个MAX_ARRAY_SIZE和MAX_VALUE 中的满足条件的值。
 1     @SuppressWarnings("unchecked")
 2     public <T> T[] toArray(T[] a) {
 3         // Estimate size of array; be prepared to see more or fewer elements
 4         int size = size();
 5         T[] r = a.length >= size ? a :
 6                   (T[])java.lang.reflect.Array
 7                   .newInstance(a.getClass().getComponentType(), size);
 8         Iterator<E> it = iterator();
 9 
10         for (int i = 0; i < r.length; i++) {
11             if (! it.hasNext()) { // fewer elements than expected
12                 if (a == r) {
13                     r[i] = null; // null-terminate
14                 } else if (a.length < i) {
15                     return Arrays.copyOf(r, i);
16                 } else {
17                     System.arraycopy(r, 0, a, 0, i);
18                     if (a.length > i) {
19                         a[i] = null;
20                     }
21                 }
22                 return a;
23             }
24             r[i] = (T)it.next();
25         }
26         // more elements than expected
27         return it.hasNext() ? finishToArray(r, it) : r;
28     }
  1. i表示当前的迭代的元素的数量,传入的参数a的大小,以及size返回的大小
  2. 如果是比预期少的元素,需要分情况讨论,r引用的就是a,则让a数组位置i为null。
  3. r引用不是a。说明a.length<size,新的数组说明是根据size新建的数组。如果a的长度小于i,说明这些值没办法放入到a中,则需要返回自建建立的数组而没办法返回原先的参数a,所有只要对r进行截断后返回就可以了
  4. 如果是a的长度>i,这说明了传入的参数a是可以放入足够的参数的,这里将r中的所有元素复制到a中,并进行截断然后返回,则让a数组位置i为null。
  5. 下同toArray().

博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3