ArrayList源碼閱讀筆記(基於JDk1.8)

關鍵常量:

private static final int DEFAULT_CAPACITY = 10; 當沒有其餘參數影響數組大小時的默認數組大小
private static final Object[] EMPTY_ELEMENTDATA = {}; 若是elementData用這個變量初始化,則DEFAULT_CAPACITY不會參與數組大小的運算
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; 若是elementData用這個變量初始化,則DEFAULT_CAPACITY會參與數組大小的運算,只有ArrayList()中有調用
transient Object[] elementData; 實際存儲數據的數組
private int size; 數組大小
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; 之因此減8是由於不一樣的vm有不一樣的保留字會佔用一部分容量
 

概述:

  ArrayList是基於數組實現的一個有序的列表,容許添加null值.除了List接口中的方法外,還實現了一些操做數組元素和大小的方法,具體下面會列舉。每一個ArrayList實例都有一個元素數,即size屬性,這個屬性標註了在實例中包含了多少個元素,這些元素存儲在elementData這個數組中,當實例的容量不足時,會調用grow方法進行擴容,一般狀況下每次擴大一半容量,可是有兩種特殊狀況,一種是手動指定的容量大於當前容量的1.5倍時會按照指定容量擴容,另外一種是當前容量的1.5倍大於MAX_ARRAY_SIZE這個值的時候會擴容至Integer.MAX_VALUE或MAX_ARRAY_SIZE。
 

主要方法:

一、構造方法

public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
public ArrayList(int initialCapacity) {    //指定容量
        if (initialCapacity > 0) {        //指定容量>0,則按照指定的容量構建數組
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {    //指定容量=0,則構造默認空數組
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);
        }
    }
public ArrayList(Collection<? extends E> c) {        //經過一個集合構造數組
        elementData = c.toArray();
        if ((size = elementData.length) != 0) {        //參數集合不爲空,則將實例構形成Object[]
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {        //參數集合爲空,則將實例構形成默認空數組
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

二、新增

public boolean add(E e) {
        ensureCapacityInternal(size + 1);      //擴容操做
        elementData[size++] = e;
        return true;
    }
public void add(int index, E element) {  //添加元素到指定位置
        rangeCheckForAdd(index);    //檢查index是否越界

        ensureCapacityInternal(size + 1); 
        System.arraycopy(elementData, index, elementData, index + 1,size - index);
        elementData[index] = element;
        size++;
    }
    public boolean addAll(Collection<? extends E> c) {    //將參數集合添加至實例
        Object[] a = c.toArray();
        int numNew = a.length;
        ensureCapacityInternal(size + numNew);  
        System.arraycopy(a, 0, elementData, size, numNew);
        size += numNew;
        return numNew != 0;
    }
 public boolean addAll(int index, Collection<? extends E> c) {    //將參數集合添加至實例指定位置
        rangeCheckForAdd(index);    //檢查index是否越界

        Object[] a = c.toArray();
        int numNew = a.length;
        ensureCapacityInternal(size + numNew);  // Increments modCount

        int numMoved = size - index;        //這裏要注意,插入前會將原數組從index位置分開
        if (numMoved > 0)
            System.arraycopy(elementData, index, elementData, index + numNew,
                             numMoved);

        System.arraycopy(a, 0, elementData, index, numNew);
        size += numNew;
        return numNew != 0;
    }

三、覆蓋

 public E set(int index, E element) {        //新增會將index位置以後的元素依次後移,而覆蓋會將index位置的元素替換,對其餘位置的元素沒有影響
        rangeCheck(index);

        E oldValue = elementData(index);
        elementData[index] = element;
        return oldValue;
    }

四、讀取

 public E get(int index) {
        rangeCheck(index);

        return elementData(index);
    }

五、刪除

public E remove(int index) {        
        rangeCheck(index);

        modCount++;
        E oldValue = elementData(index);

        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,        //刪除元素以後會將index以後的元素依次向前一位
                             numMoved);
        elementData[--size] = null; // clear to let GC do its work

        return oldValue;
    }
public boolean remove(Object o) {
        if (o == null) {
            for (int index = 0; index < size; index++)        //遍歷數組直到找到指定元素並刪除
                if (elementData[index] == null) {
                    fastRemove(index);
                    return true;
                }
        } else {
            for (int index = 0; index < size; index++)        //遍歷數組直到找到指定元素並刪除
                if (o.equals(elementData[index])) {
                    fastRemove(index);
                    return true;
                }
        }
        return false;
    }

六、清空

public void clear() {
        modCount++;

        for (int i = 0; i < size; i++)
            elementData[i] = null;

        size = 0;
    }

七、擴容

private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {    //當使用第一種構造方法時,第一次執行擴容方法會進入這個分支,將容量擴展爲默認大小(10)
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        ensureExplicitCapacity(minCapacity);
    }

    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;
        if (minCapacity - elementData.length > 0)    //若是參數長度大於數組長度則會擴容
            grow(minCapacity);
    }
private void grow(int minCapacity) {    
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);    //默認每次增加爲1.5倍
        if (newCapacity - minCapacity < 0)        //特例1:參數大於數組長度的1.5倍,此時按照參數擴容
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)    //特例2:數組長度的1.5倍大於MAX_ARRAY_SIZE,此時將數組擴容至MAX_ARRAY_SIZE 或Integer.MAX_VALUE
            newCapacity = hugeCapacity(minCapacity);
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

八、Fail-Fast機制

ArrayList的迭代器也具有快速失敗機制,具體是經過checkForComodification()進行控制:
final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
若是併發線程對實例進行增刪操做,則迭代器會拋出異常以防止在不肯定的時間發生某種行爲帶來的未知風險
相關文章
相關標籤/搜索