1. 程式人生 > >JDK1.8 ArrayList 擴容詳解

JDK1.8 ArrayList 擴容詳解

arraylist這個資料結構比較簡單,總體來說,arraylist 底層結構是陣列,他的很多方法都是從陣列上面演變而來的,下面分析下arraylist的擴容機制, 每次在add()一個元素時,arraylist都需要對這個list的容量進行一個判斷。如果容量夠,直接新增,否則需要進行擴容。在1.8 arraylist這個類中,擴容呼叫的是grow()方法,通過grow()方法中呼叫的Arrays.copyof()方法進行對原陣列的複製,在通過呼叫System.arraycopy()方法進行復制,達到擴容的目的 幾個重要的初始化值
儲存陣列元素的緩衝區
// non-private to simplify nested class access
transient Object[] elementData; 
預設空陣列元素
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
預設初始化容量
private static final int DEFAULT_CAPACITY = 10;
陣列的大小
private int size;
記錄被修改的次數
protected transient int modCount = 0;
陣列的最大值
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8
幾個重要的方法 一個空的構造方法
預設陣列的長度為10
public ArrayList() {
    this.elementData  = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
新增元素的方法,
public boolean add(E e) {
擴充長度,在原來的大小上面加1
// Increments modCount!!
    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) {
如果這個陣列等於空,返回最大的容量,否則,還是原來的容量
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        return Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    return minCapacity;
    }
確認擴充套件容量
private void ensureExplicitCapacity(int minCapacity) {
修改次數加1
    modCount++;
如果容量不夠,呼叫增加容量方法
    // overflow-conscious code
    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);
新容量比老容量小,那麼新的容量就是老的容量
    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);
}
陣列工具類中的複製方法
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) {
    @SuppressWarnings("unchecked")
獲得者陣列物件
    T[] copy = ((Object)newType == (Object)Object[].class)
        ? (T[]) new Object[newLength]
        : (T[]) Array.newInstance(newType.getComponentType(), newLength);

呼叫系統的方法增加陣列容量
    System.arraycopy(original, 0, copy, 0,Math.min(original.length, newLength));
    return copy;
}