ArrayList源碼、實現源碼

屬性:

//用於序列化的id
private static final long serialVersionUID = 8683452581122892189L;

//默認構造方法的容量
private static final int DEFAULT_CAPACITY = 10;

//空數組,構造方法中參數爲0時使用--->new ArrayList(0)
private static final Object[] EMPTY_ELEMENTDATA = {};

//空數組,默認構造方法使用--->new ArrayList()
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

//臨時存放元素的數組,使用transient修飾,不會被序列化
transient Object[] elementData; 

//元素實際個數
private int size;

//數組能分配的最大內存,超出會OutOfMemoryError
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

構造方法:

//構造方法一,傳入容量
public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            //添加元素時會擴容
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }


//構造方法二,不傳入初始容量
public ArrayList() {
        //當添加第一個元素時,擴容到默認大小10
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

   
//構造方法三,傳入一個集合,將其轉化爲ArrayList
public ArrayList(Collection<? extends E> c) {
        //集合轉數組
        elementData = c.toArray();
        
        if ((size = elementData.length) != 0) {
            // 檢查c.toArray()返回的是不是Object[]類型,如果不是,重新拷貝成Object[].class類型 
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            // 如果c的空集合,則初始化爲空數組EMPTY_ELEMENTDATA
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

ArrayList的add(E e)方法

  大致思路:  首先判斷是否需要擴容,先需要計算該集合的容量,如果這個集合是空集合的話,給定默認的容量爲10,如果不是空集合的話再進行擴容,新容量的大小爲原容量的1.5倍。如果新容量的大小小於需要容量,則以需要容量爲準。如果新容量的大小大於最大容量,則以最大容量爲準,最終實現數組的拷貝。

 

public boolean add(E e) {
    // 檢查是否需要擴容
    ensureCapacityInternal(size + 1);
    // 把元素插入到最後一位
    elementData[size++] = e;
    return true;
}

private void ensureCapacityInternal(int minCapacity) {
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}

//計算容量
private static int calculateCapacity(Object[] elementData, int minCapacity) {
    // 如果是空數組DEFAULTCAPACITY_EMPTY_ELEMENTDATA,就初始化爲默認大小10
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        return Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    return minCapacity;
}

private void ensureExplicitCapacity(int minCapacity) {
    modCount++;

    if (minCapacity - elementData.length > 0)
        // 擴容
        grow(minCapacity);
}

private void grow(int minCapacity) {
    int oldCapacity = elementData.length;
    // 新容量爲舊容量的1.5倍
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    // 如果新容量發現比需要的容量還小,則以需要的容量爲準
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    // 如果新容量已經超過最大容量了,則使用最大容量
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    // 以新容量拷貝出來一個新數組
    elementData = Arrays.copyOf(elementData, newCapacity);
}

add(int index, E element)方法

public void add(int index, E element) {
        //檢查是否越界
        rangeCheckForAdd(index);
        //檢查是否需要擴容
        ensureCapacityInternal(size + 1);  
        //將index及其後的元素向後移動一位,空出index的位置
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
     //空出的位置存放加入的元素
        elementData[index] = element;
     //數量加一
        size++;
    }

 

addAll(Collection<? extends E> c)方法

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;
    }

get(int index)方法

public E get(int index) {
    // 檢查是否越界
    rangeCheck(index);
    // 返回數組index位置的元素
    return elementData(index);
}

private void rangeCheck(int index) {
    if (index >= size)
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

E elementData(int index) {
    return (E) elementData[index];
}

remove(int index)方法

public E remove(int index) {
    // 檢查是否越界
    rangeCheck(index);

    modCount++;
    // 獲取index位置的元素
    E oldValue = elementData(index);

    // 如果index不是最後一位,則將index之後的元素往前挪一位
    int numMoved = size - index - 1;
    if (numMoved > 0)
        System.arraycopy(elementData, index+1, elementData, index, numMoved);

    // 將最後一個元素刪除,幫助GC
    elementData[--size] = null; // clear to let GC do its work

    // 返回舊值
    return oldValue;
}

 

 

 

總結

(1)ArrayList內部使用數組存儲元素,當數組長度不夠時進行擴容,每次加一半的空間,ArrayList不會進行縮容;

(2)ArrayList支持隨機訪問,通過索引訪問元素極快,時間複雜度爲O(1);

(3)ArrayList支持求並集,調用addAll(Collection<? extends E> c)方法即可;

(4)ArrayList支持求交集,調用retainAll(Collection<? extends E> c)方法即可;

(5)ArrayList支持求單向差集,調用removeAll(Collection<? extends E> c)方法即可;

(6)ArrayList有兩種迭代器,支持向前向後遍歷。

(7)ArrayList底層基於數組,所以除了迭代器,也可以使用循環遍歷。

(8)ArrayList查詢快,增刪慢,線程不安全。

 

ArrayList查詢快的原因是因爲底層是數組,只需要獲取數組下標即可獲得元素,對於增刪慢的原因是因爲ArrayList是需要移動元素,導致增刪慢。

發佈了113 篇原創文章 · 獲贊 32 · 訪問量 7402
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章