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++;
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章