JDK1.8 ArrayList源码分析

本篇主要对添加元素,和扩容机制进行分析

属性

 /**
     * 序列号
     */
    private static final long serialVersionUID = 8683452581122892189L;

    /**
     * 默认初始容量
     */
    private static final int DEFAULT_CAPACITY = 10;

    /**
     *
     * 共享的空数组用于实例空数组
     */
    private static final Object[] EMPTY_ELEMENTDATA = {};

    /**
     * 共享的空数组用于实例化默认大小的空数组,用于区分EMPTY_ELEMENTDATA,
     * 当添加了第一元素的,数组容量扩充为DEFAULT_CAPACITY,即10
     */
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

    /**
     * 存储数据的数组,
     */
    transient Object[] elementData; // non-private to simplify nested class access

    /**
     * 当前元素个数
     */
    private int size;

构造方法

    // 参数:initialCapacity 指定大小初始化容量
    public ArrayList(int initialCapacity) {
    //  初始化容量>0
        if (initialCapacity > 0) {
//     new Object[initialCapacity],创建指定大小的数组,并赋值给elementData
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
//            如果initialCapacity 0,则把EMPTY_ELEMENTDATA这个空数组,赋值给elementData
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
//            如果initialCapacity<0,抛出异常
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }


    /**
     * 无参构造,DEFAULTCAPACITY_EMPTY_ELEMENTDATA赋值给elementData
     */
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }


    public ArrayList(Collection<? extends E> c) {
//   Collection转换为数组,并赋值给 elementData
        elementData = c.toArray();
//        如果元素个数不为0
        if ((size = elementData.length) != 0) {
            // 如果c.toArray不是Object类型
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            // 如果为0,用EMPTY_ELEMENTDATA替换,赋值给elementData
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }
  • ArrayList():在放入第一个元素的时候,扩容到默认大小10;
  • ArrayList(int initialCapacity):创建一个initialCapacity大小的数组给elementData
  • ArrayList(Collection<? extends E> c):将Collection类型的集合转换为数组,赋值给elementData

add(E e)

我们来看看整个add(E e)的过程

  public boolean add(E e) {
  		// 确认容量
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        //赋值
        elementData[size++] = e;
        return true;
    }
    -------------------------------------------------------
    
 private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            /**
             * 这里就是为甚么 new ArrayList()默认为10 的原因
             * 用无参构造函数进行初始化的时候:
             * 把DEFAULTCAPACITY_EMPTY_ELEMENTDATA赋值给了elementData
             * 在第一次添加元素时进入到这里
             * 经过max计算minCapacity=10;
             * 然后调用ensureExplicitCapacity扩容到10,
             *
             */
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        //确认是否进行扩容
        ensureExplicitCapacity(minCapacity);
    }
	-------------------------------------------------------
	    private void ensureExplicitCapacity(int minCapacity) {
//       modCount:记录操作次数,modCount++
        modCount++;
        // overflow-conscious code
//        如果最小的容量-当前数组长度>0
        if (minCapacity - elementData.length > 0)
//          扩容
            grow(minCapacity);
    }
    -------------------------------------------------------
        private void grow(int minCapacity) {
        // overflow-conscious code
//      oldCapacity 原来容量;
        int oldCapacity = elementData.length;
//        新的容量 = 原来容量+原来容量/2
        int newCapacity = oldCapacity + (oldCapacity >> 1);
//        如果新的容量-最小容量<0
        if (newCapacity - minCapacity < 0)
//            新的容量=最小容量
            newCapacity = minCapacity;
//       如果新的容量大于规定的最大容量
        if (newCapacity - MAX_ARRAY_SIZE > 0)
//
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
//      把原来数组数组,复制到新数组中,完成扩容
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

ArrayList添加元素操作,就这么个流程,先确认是否扩容,然后在放入元素

  1. 如果使用new ArrayList()创建对象,第一个元素的时候,扩容到默认大小10;
  2. 如果是其他情况,则当size+1-elementData.length>0时(当前元素个数+1-当前容量>0),进行扩容

扩容方式
新的容量 = 原来容量+原来容量/2: int newCapacity = oldCapacity + (oldCapacity >> 1)
这里用到了位运算:可以参考我的另外一篇文章:位运算

add(int index, E element)

    public void add(int index, E element) {
        rangeCheckForAdd(index);

        ensureCapacityInternal(size + 1);  // Increments modCount!!
        //这个arraycopy是native方法,大该意思大家还是能看出来;index后面的元素
        // 通通后移一位
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        //插入元素                 
        elementData[index] = element;
        size++;
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章