1. 程式人生 > >資料結構(一)ArrayList原始碼分析

資料結構(一)ArrayList原始碼分析

一、相關特性:

1、關係圖:
這裡寫圖片描述

2、特點:
* 元素所佔儲存空間是連續的
* 基於陣列實現,容量可自增
* 可通過角標獲取指定位置的元素
* 查詢快(基於陣列索引),增刪慢(涉及到陣列複製、移動和擴容)

二、建構函式和變數:

1、變數:

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

    //首次預設擴充套件的值
private static final int DEFAULT_CAPACITY = 10; //空陣列 private static final Object[] EMPTY_ELEMENTDATA = {}; //預設的elementData private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; //元素的儲存結構為陣列 transient Object[] elementData; //陣列長度 private int size; ......

2、建構函式

(1)使用無參構造建立一個ArrayList,預設陣列為空{}

public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

(2)可通過構造指定陣列的大小

public ArrayList(int initialCapacity) {
    if (initialCapacity > 0) {
        this.elementData = new Object[initialCapacity];
    } else if (initialCapacity == 0
) { //如果傳入0,陣列為空陣列 this.elementData = EMPTY_ELEMENTDATA; } else { throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); } }

(3)可傳入一個集合

public ArrayList(Collection<? extends E> c) {
    //轉為陣列,賦值給elementData
    elementData = c.toArray();
    if ((size = elementData.length) != 0) {
        // c.toArray might (incorrectly) not return Object[] (see 6260652)
        //這個啥bug?
        if (elementData.getClass() != Object[].class)
            elementData = Arrays.copyOf(elementData, size, Object[].class);
    } else {
        // 空陣列
        this.elementData = EMPTY_ELEMENTDATA;
    }
}

c.toArray might (incorrectly) not return Object[]:

List<String> dataList = new ArrayList<String>();  
dataList.add("one");  
dataList.add("two");  
Object[] listToArray = dataList.toArray();  

通過toArray轉為Object陣列(內部實現不同),但是listToArray不一定能放置Object物件,出現這種情況就通過Arrays.copyOf來建立一個Object陣列,就可以存放任意類似的元素了。

三、新增元素:

1、隊尾新增元素
* 進行資料長度判斷,不夠進行擴容
* 隊尾插入元素

public boolean add(E e) {
    //(1)擴容
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    //(2)賦值
    elementData[size++] = e;
    return true;
}

(1)擴容

private void ensureCapacityInternal(int minCapacity) {
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        //所需最小容量
        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) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    //1.5倍擴容
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    //如果還不滿足,直接擴容到minCapacity
    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);
}

擴容機制:
* 建立一個空陣列elementData,第一次插入資料時擴容到10
* 如果elementData長度不夠就直接擴容1.5倍
* 如果還不夠,就使用需要的長度作為elementData的長度

2、指定位置新增元素
* 進行資料長度判斷,不夠進行擴容
* 進行陣列複製
* 插入元素

public void add(int index, E element) {
    if (index > size || index < 0)
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    //(1)確保陣列長度足夠
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    //(2)將資料向後移動一位
    System.arraycopy(elementData, index, elementData, index + 1, size - index);
    //(3)插入元素
    elementData[index] = element;
    size++;
}

(1)陣列擴容同上
(2)陣列複製

 * @param src  原陣列
 * @param srcPos 原陣列要複製的開始位置
 * @param dat 目標陣列
 * @param dstPos 目標陣列的開始位置
 * @param length 要複製的長度
 *  /

public static native void arraycopy(Object src, int srcPos,
    Object dst, int dstPos, int length);

四、刪除元素:

public E remove(int index) {
    if (index >= size)
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));

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

    int numMoved = size - index - 1;
    //陣列前移
    if (numMoved > 0)
        System.arraycopy(elementData, index+1, elementData, index,
                         numMoved);
    //最後位置的元素置null
    elementData[--size] = null; // clear to let GC do its work

    return oldValue;
}

五、修改元素:

public E set(int index, E element) {
    if (index >= size)
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    //獲取當前位置元素
    E oldValue = (E) elementData[index];
    //當前位置置為新元素
    elementData[index] = element;
    return oldValue;
}

六、獲取元素:

public E get(int index) {
    if (index >= size)
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    return (E) elementData[index];
}

根據索引獲取陣列