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

ArrayList源碼分析

注:JDK1.7
首先先來個總體的認識,ArrayList底層是用數組實現的。在插入值時如果超過了當前數組的大小,則會進行擴容操作,每次增加的大小爲原來大小的“一半”(偶數一半,奇數減一的一半),並且按照新的大小新建一個相同類型的數組,然後將原數組中的值copy進新的數組,並修改引用。
默認創建ArrayList情況下:
這裏寫圖片描述
然後瞭解下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;
1.
//首先會調用構造函數ArrayList()
public ArrayList() {
    //調用父類構造函數
    super();
    //初始化elementData,ArrayList實際用來存儲信息的數組
    this.elementData = EMPTY_ELEMENTDATA;
}

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

這樣一個空的ArrayList就創建完畢了,當然,我們還可以自己定義初始數組的大小。之後都以默認新建方式說明。
List<String> list = new ArrayList<String>(20);

public ArrayList(int initialCapacity) {
    super();
    if (initialCapacity < 0)
        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;//默認大小爲10
1.
//list.add("1") 調用函數,添加成功時返回true
public boolean add(E e) {
    //檢查數組容量,並進行擴容操作,size此時爲0
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}

2.
//檢查數組容量,並在超過容量時擴容
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 > 0)
        //擴容操作
        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 >> 1);
    //newCapacity = 0,minCapacity = 10
    if (newCapacity - minCapacity < 0)
        //newCapacity = 10
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    // minCapacity is usually close to size, so this is a win:
    //新建一個通類型數組,copy舊值並修改elementData引用
    //現在newCapacity = 10
    elementData = Arrays.copyOf(elementData, newCapacity);
}

3.
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, 0, copy, 0,
                         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引用。完成擴容操作後當前的值就能放的進數組了,然後將值存入即可。
這裏寫圖片描述
這裏會遇到一些有意思的東西,順便回顧下

//泛型,這裏有3T
//第一個T:申明T爲一個泛型
//第二個T:返回一個T類型數組
//第三個T:一個形參爲T類型數組
public static <T> T[] copyOf(T[] original ...)
//當然還可以寫成這樣,∠( ᐛ 」∠)_
public static <ᐛ> ᐛ ᐛ(ᐛ ᐛ){
    return ᐛ;
}

這裏寫圖片描述

然後還有一個add函數允許我們在指定位置添加數據
相關源代碼

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

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

Arrays.class
private void rangeCheckForAdd(int index) {
    if (index > size || index < 0)
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

這裏寫圖片描述


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 = 0; i < size; i++)
            if (elementData[i]==null)
                return i;
    } else {
        for (int i = 0; i < size; i++)
            if (o.equals(elementData[i]))
                return i;
    }
    return -1;
}

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

isEmpty()函數

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

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

remove()函數

相關源代碼

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

    int numMoved = size - index - 1;
    //如果index不是數組的最後一個下標值
    if (numMoved > 0)
        //進行拷貝操作,將從index+1下標開始到最後一個的值都往前移動一位
        System.arraycopy(elementData, index+1, 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 = 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;
}
//和上面按下標刪值的過程一樣
private void fastRemove(int index) {
    //修改次數+1
    modCount++;
    //和上面按下標刪值的過程一樣
    int numMoved = size - index - 1;
    if (numMoved > 0)
    System.arraycopy(elementData, index+1, 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, 0, fromIndex, toIndex);
}
//判斷fromIndex,toIndex是否數組越界
static void subListRangeCheck(int fromIndex, int toIndex, int size) {
    if (fromIndex < 0)
        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 = -1; // 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 + 1;
        //返回i處的值
        return (E) elementData[lastRet = i];
    }
    final void checkForComodification() {
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
    }
}

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章