集合3-AbstractCollection源码分析

Abstract类实现了接口的大部分方法,除了Iterator以及size方法,抽象实现类实现了接口的默认实现,方便了子类的实现,接口的适配器模式

集合3-AbstractCollection源码分析_第1张图片

AbstractCollection

public abstract class AbstractCollection implements Collection

public Object[] toArray():创建size大小的Object数组,通过迭代器遍历数组大小范围的集合元素将其元素引用复制到数组当中,判断集合的元素是否大于小于等于预期大小(size的大小)分不同的处理情况来处理。
public T[] toArray(T[] a):如果参数数组的大小size,则用反射创建一个T类型的数组,否则就是用这个数组的引用,还是通过迭代器遍历数组范围的集合元素将其元素引用复制到数组当中,判断集合的元素是否大于小于等于预期大小(size的大小)分不同的处理情况来处理。

// (1) 如果参数数组长度大于等于集合的长度,则将当前集合的元素复制到参数数组当中
// (2) 如果参数数组的长度小于集合的长度,则通过数组的反射创建T类型的新数组来容纳集合元素

 public  T[] toArray(T[] a) {
        // Estimate size of array; be prepared to see more or fewer elements
        int size = size();
        T[] r = a.length >= size ? a :
                  (T[])java.lang.reflect.Array
                  .newInstance(a.getClass().getComponentType(), size);
        Iterator it = iterator();

        for (int i = 0; i < r.length; i++) {
            if (! it.hasNext()) { // fewer elements than expected 在数组长度范围内出现没有下一个元素的情况,说明集合大小小于数组的长度
                if (a == r) { //如果a 和 r 所引用的数组相同,则将剩下的数组元素都赋值为null,作为集合元素的结束标志
                    r[i] = null; // null-terminate
                } else if (a.length < i) {//如果参数数组的长度小于集合的长度,也就是r是通过反射新创建的数组,则通过Arrays.copyOf方法截短返回
                    return Arrays.copyOf(r, i);
                } else {//r是通过反射新创建的数组,但是参数数组长度大于集合长度,
                          //即a的长度大于新创建的r数组的长度(这在单线程情况下不可能发生,但是在
                          //并发情况下参数数组的长度可能发生变化),则将r数组复制到a数组当中,并
                          //将参数数组多的元素设置为null
                    System.arraycopy(r, 0, a, 0, i);//将创建的r数组所有元素复制到a数组当中
                    if (a.length > i) {
                        a[i] = null;
                    }
                }
                return a;
            }
            r[i] = (T)it.next(); //类型转换,可能会抛出ClassCastException异常
        }
        // more elements than expected
        // 如果集合长度大于数组的长度则拓展数组r,否则(集合长度正好等于数组的长度)直接返回数组r
        return it.hasNext() ? finishToArray(r, it) : r;
    }

private static T[] finishToArray(T[] r, Iterator it) 数组扩容的私有实现方法

 /**
     *  (1)对数组进行扩容:即创建一个更长的数组,然后将原数组的内容复制到新数组中
     *  (2)扩容大小:cap + cap/2 +1
     *  (3)扩容前需要先判断是否数组长度是否溢出
     */
    private static  T[] finishToArray(T[] r, Iterator it) {
        int i = r.length;//记录数组有效长度
        while (it.hasNext()) {
            int cap = r.length;//数组最大可用容量
            if (i == cap) {//当数组有效长度和数组最大可用容量相等时,再次扩容
                int newCap = cap + (cap >> 1) + 1; //扩容为 cap + cap/2 +1
                // overflow-conscious code
                if (newCap - MAX_ARRAY_SIZE > 0)//新扩大的容量发生溢出
                    newCap = hugeCapacity(cap + 1);
                //Arrays.copyOf方法内部创建了一个新的长度为newCap数组,
                //并将元素复制到这个新的数组当中,底层调用的是System.arraycopy native方法
                r = Arrays.copyOf(r, newCap);
            }
            r[i++] = (T)it.next();//数组有效长度自增,并复制引用
        }
        // trim if overallocated 截短数组长度到有效长度
        return (i == r.length) ? r : Arrays.copyOf(r, i);
    }

  /**
     * 判断数组容量是否溢出,最大为整型数据的最大值
     */
    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow 超出整型的最大值则数值溢出为负值
            throw new OutOfMemoryError
                ("Required array size too large");
        return (minCapacity > MAX_ARRAY_SIZE) //如果大于最大容量则返回整数的最大值,否则返回集合的最大容量。
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

数组的最大可分配大小为整数的最大值,但是有些虚拟机会保留几个字节大小的空间存储头部,所以为了保险起见最大可分配的数组大小为整数最大值-8,否则会抛出内存溢出错误

 /**
     * The maximum size of array to allocate.
     * Some VMs reserve some header words in an array.
     * Attempts to allocate larger arrays may result in
     * OutOfMemoryError: Requested array size exceeds VM limit
     */
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

public boolean contains(Object o) **
** public boolean remove(Object o)

都是通过迭代器进行遍历集合元素,对参数为null单独处理,如果下一个元素的值为null执行相对应的操作(集合允许null元素)

批量操作是通过对参数集合进行遍历,并执行相关的操作

public boolean containsAll(Collection c)、public boolean addAll(Collection c)、public boolean removeAll(Collection c)、public boolean retainAll(Collection c)
初始化一个modified标志,对于批量操作只要有一个参数集合的元素被操作成功并使得集合发生改变则返回true,而不是所有参数集合都被成功操作。

你可能感兴趣的:(集合3-AbstractCollection源码分析)