天天看點

Java:ArrayList源碼分析(JDK1.7)

ArrayList源碼分析

注:JDK1.7

首先先來個總體的認識,ArrayList底層是用數組實作的。在插入值時如果超過了目前數組的大小,則會進行擴容操作,每次增加的大小為原來大小的“一半”(偶數一半,奇數減一的一半),并且按照新的大小建立一個相同類型的數組,然後将原數組中的值copy進新的數組,并修改引用。

預設建立ArrayList情況下:

Java:ArrayList源碼分析(JDK1.7)

然後了解下ArrayList繼承和實作的類和接口

public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
           

總體有一個認知後從建立一個ArrayList講起吧。

初始化

首先建立一個ArrayList:

List<String> list = new ArrayList<String>();

相關源代碼

private static final Object[] EMPTY_ELEMENTDATA = {};
private transient Object[] elementData;

//首先會調用構造函數ArrayList()
public ArrayList() {
    //調用父類構造函數
    super();
    //初始化elementData,ArrayList實際用來存儲資訊的數組
    this.elementData = EMPTY_ELEMENTDATA;
}


//父類構造函數就略過了,在調用父類構造函數時會初始化modCount 成員變量,
//之後ArrayList就使用該變量來記錄自身經曆的修改次數。
AbstractList.class
protected transient int modCount = ; //修改/操作次數
           

這樣一個空的ArrayList就建立完畢了,當然,我們還可以自己定義初始數組的大小。之後都以預設建立方式說明。

List<String> list = new ArrayList<String>(20);

public ArrayList(int initialCapacity) {
    super();
    if (initialCapacity < )
        throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
    this.elementData = new Object[initialCapacity];
}
           

add()函數

相關源代碼

/**
* The size of the ArrayList (the number of elements it contains).
*
* @serial
*/
private int size;//記錄目前ArrayList儲存的資料量
private static final int DEFAULT_CAPACITY = ;//預設大小為10

//list.add("1") 調用函數,添加成功時傳回true
public boolean add(E e) {
    //檢查數組容量,并進行擴容操作,size此時為0
    ensureCapacityInternal(size + );  // Increments modCount!!
    elementData[size++] = e;
    return true;
}


//檢查數組容量,并在超過容量時擴容
private void ensureCapacityInternal(int minCapacity) {
    //目前ArrayList(elementData 數組)為空,
    //目前minCapacity = 1 ,DEFAULT_CAPACITY = 10,是以minCapacity = 10
    if (elementData == EMPTY_ELEMENTDATA) {
        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    //現在minCapacity = 10
    ensureExplicitCapacity(minCapacity);
}
//當超過容量時擴容數組
private void ensureExplicitCapacity(int minCapacity) {
    //記錄一次插入操作
    modCount++;
    // overflow-conscious code
    //超過數組容量,進行擴容,minCapacity = 10 > (elementData.length = 0)
    if (minCapacity - elementData.length > )
        //擴容操作
        grow(minCapacity);
}
//擴容
private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    //newSize = oldSize + oldSize >> 1 (等價于偶數/2,奇數-1/2)。
    //現在elementData = {},newCapacity = 0
    int newCapacity = oldCapacity + (oldCapacity >> );
    //newCapacity = 0,minCapacity = 10
    if (newCapacity - minCapacity < )
        //newCapacity = 10
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > )
        newCapacity = hugeCapacity(minCapacity);
    // minCapacity is usually close to size, so this is a win:
    //建立一個通類型數組,copy舊值并修改elementData引用
    //現在newCapacity = 10
    elementData = Arrays.copyOf(elementData, newCapacity);
}


Arrays.class
//即Arrays.copyOf函數,現在elementData = {} 空數組,newLength = 10
public static <T> T[] copyOf(T[] original, int newLength) {
    return (T[]) copyOf(original, newLength, original.getClass());
}
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
    //因為建立時時ArrayList<String>
    //(Object)newType = 'class [Ljava.lang.String;' String數組類
    //(Object)Object[].class = 'class [Ljava.lang.Object;' Object數組類
    //是以(Object)newType == (Object)Object[].class = false
    //執行(String[]) Array.newInstance('class java.lang.String'->String類, newLength)
    T[] copy = ((Object)newType == (Object)Object[].class)
            ? (T[]) new Object[newLength]
            : (T[]) Array.newInstance(newType.getComponentType(), newLength);
    //從original的0下标處開始複制Math.min(original.length, newLength)
    //個值拷貝給copy,并從copy的0下标處開始指派
    System.arraycopy(original, , copy, ,
                         Math.min(original.length, newLength));
    return copy;
}
//即Array.newInstance
//按照提供的類型和大小生成一個該類型的數組
//傳回Object類型,因為數組類是Object類的子類,是以之後強轉成對應的數組類即可
public static Object newInstance(Class<?> componentType, int length)
        throws NegativeArraySizeException {
        return newArray(componentType, length);
}
           

讓我們接着之前建立的ArrayList講,運作

list.add("1")

,可以看上面給出的相關源代碼中的注釋,可以看到add如果不涉及擴容的話基本上隻做了modCount++和把值存入elementData數組中,非常簡潔明了,當存入的資訊數大于目前數組容量時會重新計算一個擴容大小,即

newSize = oldSize + (oldSize >> 1)

,然後根據新的大小和類型建立一個新的數組,然後将舊資訊copy到新的數組中,然後修改elementData引用。完成擴容操作後目前的值就能放的進數組了,然後将值存入即可。

Java:ArrayList源碼分析(JDK1.7)

這裡會遇到一些有意思的東西,順便回顧下

//泛型,這裡有個T
//第一個T:申明T為一個泛型
//第二個T:傳回一個T類型數組
//第三個T:一個形參為T類型數組
public static <T> T[] copyOf(T[] original ...)
//當然還可以寫成這樣,∠( ᐛ 」∠)_
public static <ᐛ> ᐛ ᐛ(ᐛ ᐛ){
    return ᐛ;
}
           
Java:ArrayList源碼分析(JDK1.7)

然後還有一個add函數允許我們在指定位置添加資料

相關源代碼

public void add(int index, E element) {
    //檢測指定位置是否合法
    rangeCheckForAdd(index);

    //和上面講的一樣,判斷是否擴容和增加modCount值
    ensureCapacityInternal(size + );  // Increments modCount!!
    //上面在copyOf函數中出現過,就是把指定位置處空出來,
    //指定位置後的值儲存下标值都向後移動一位,可以看下圖,比較直覺一點
    System.arraycopy(elementData, index, elementData, index + ,
                         size - index);
    elementData[index] = element;
    size++;
}

Arrays.class
private void rangeCheckForAdd(int index) {
    if (index > size || index < )
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
           
Java:ArrayList源碼分析(JDK1.7)

get()函數

相關源代碼

//擷取index下标處的值
public E get(int index) {
    //index是否超過數組大小
    rangeCheck(index);
    return elementData(index);
}
private void rangeCheck(int index) {
    if (index >= size)
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
//通知編譯器對下面這段代碼的警告保持沉默,即忽略該段代碼的警告
@SuppressWarnings("unchecked")
E elementData(int index) {
    return (E) elementData[index];
}
           

總體很簡單,也不多說什麼了。

indexOf()函數

相關源代碼

//傳回o在ArrayList中第一次出現時的下标值,不存在則傳回-1
public int indexOf(Object o) {
    //為null時
    if (o == null) {
        for (int i = ; i < size; i++)
            if (elementData[i]==null)
                return i;
    } else {
        for (int i = ; i < size; i++)
            if (o.equals(elementData[i]))
                return i;
    }
    return -;
}

//最後出現的位置,和IndexOf原理一樣
public int lastIndexOf(Object o) {
    if (o == null) {
        for (int i = size-; i >= ; i--)
            if (elementData[i]==null)
                return i;
    } else {
        for (int i = size-; i >= ; i--)
            if (o.equals(elementData[i]))
                return i;
    }
    return -;
}
           

isEmpty()函數

相關源代碼,因為ArrayList類中有一個size變量用來記錄目前ArrayList包含的記錄數量,是以直接去檢查size是否為0即可

public boolean isEmpty() {
    return size == ;
}
           

remove()函數

相關源代碼

//根據下标值删除
public E remove(int index) {
    //判定下标值是否大于數組容量
    rangeCheck(index);
    //添加修改記錄
    modCount++;
    //擷取該下标處的值
    E oldValue = elementData(index);

    int numMoved = size - index - ;
    //如果index不是數組的最後一個下标值
    if (numMoved > )
        //進行拷貝操作,将從index+1下标開始到最後一個的值都往前移動一位
        System.arraycopy(elementData, index+, elementData, index,
                             numMoved);
    //将數組大小相應的減小一位,并将減小後的數組的最後一位置為空,、
    //以覆寫掉原來在這裡的舊值
    elementData[--size] = null; // clear to let GC do its work
    //删除成功,傳回該處的值
    return oldValue;
}
private void rangeCheck(int index) {
    if (index >= size)
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
@SuppressWarnings("unchecked")
E elementData(int index) {
    return (E) elementData[index];
}
           
//根據值删除
public boolean remove(Object o) {
    //周遊查詢是否存在相等的值
    if (o == null) {
        for (int index = ; index < size; index++)
            if (elementData[index] == null) {
                //和上面按下标删值的過程一樣
                fastRemove(index);
                return true;
            }
    } else {
        for (int index = ; index < size; index++)
            if (o.equals(elementData[index])) {
                //和上面按下标删值的過程一樣
                fastRemove(index);
                return true;
            }
    }
    return false;
}
//和上面按下标删值的過程一樣
private void fastRemove(int index) {
    //修改次數+1
    modCount++;
    //和上面按下标删值的過程一樣
    int numMoved = size - index - ;
    if (numMoved > )
    System.arraycopy(elementData, index+, elementData, index,
                             numMoved);
    elementData[--size] = null; // clear to let GC do its work
}
           

set()函數

相關源代碼

public E set(int index, E element) {
    //前面出現過很多次了,判斷index是否超過數組容量
    rangeCheck(index);
    //elementData()也出現過很多次了,傳回index下标處的值
    E oldValue = elementData(index);
    //設定新值
    elementData[index] = element;
    return oldValue;
}
           

subList(start,end)函數

相關源代碼

//傳回從fromIndex到toIndex之間的數組
public List<E> subList(int fromIndex, int toIndex) {
    //判斷fromIndex,toIndex是否數組越界
    subListRangeCheck(fromIndex, toIndex, size);
    //傳回fromIndex到toIndex之間的值
    return new SubList(this, , fromIndex, toIndex);
}
//判斷fromIndex,toIndex是否數組越界
static void subListRangeCheck(int fromIndex, int toIndex, int size) {
    if (fromIndex < )
        throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
    if (toIndex > size)
        throw new IndexOutOfBoundsException("toIndex = " + toIndex);
    if (fromIndex > toIndex)
        throw new IllegalArgumentException("fromIndex(" + fromIndex +
                                               ") > toIndex(" + toIndex + ")");
}
//因為整個SubList類太長,放上來比較占地方是以就截取了一段,基本和ArrayList相同
private class SubList extends AbstractList<E> implements RandomAccess {
    private final AbstractList<E> parent;
    private final int parentOffset;
    private final int offset;
    int size;

    SubList(AbstractList<E> parent,
                int offset, int fromIndex, int toIndex) {
        this.parent = parent;
        this.parentOffset = fromIndex;
        this.offset = offset + fromIndex;
        this.size = toIndex - fromIndex;
        this.modCount = ArrayList.this.modCount;
    }
    ......
}
           

Iterator疊代器

//常見用法,周遊
List<String> list = new ArrayList<String>();
list.add("1");
list.add("2");
list.add("3");
list.add("4");
Iterator iterator = list.iterator();
while(iterator.hasNext()){
    String s = (String)iterator.next();
}
           

相關源代碼

//建立疊代器
public Iterator<E> iterator() {
    return new Itr();
}
//截取了用到的一段
private class Itr implements Iterator<E> {
    int cursor;       // index of next element to return
    int lastRet = -; // index of last element returned; -1 if no such
    int expectedModCount = modCount;

    public boolean hasNext() {
        return cursor != size;
    }

    @SuppressWarnings("unchecked")
    public E next() {
        //檢查修改次數是否有異常
        checkForComodification();
        //下一個傳回值的下标
        int i = cursor;
        //數組越界
        if (i >= size)
            throw new NoSuchElementException();
        Object[] elementData = ArrayList.this.elementData;
        //數組中還沒有那麼多值
        if (i >= elementData.length)
            throw new ConcurrentModificationException();
        //修改遊标,進行下一輪查詢時用
        cursor = i + ;
        //傳回i處的值
        return (E) elementData[lastRet = i];
    }
    final void checkForComodification() {
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
    }
}
           

以上,基本包含了常用的ArrayList相關函數。