集合(一) - ArrayList

1、層級關係

clipboard.png

2、初始化方式

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

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

private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

第一個結論:ArrayList底層是數組數組

第二個結論:若用無參構造器的方式實例化ArrayList,只是聲明瞭數組,還未分配空間安全

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

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

private static final Object[] EMPTY_ELEMENTDATA = {};

補充第二結論:若用有參構造器的方式實例化ArrayList且initialCapacity大於0,則既聲明瞭數組,也分配了空間多線程

3、基本方法的使用

add

  • 流程圖

clipboard.png

  • 源碼解析
public boolean add(E e) {
    //校驗數組容量,若空間不夠則擴容複製生成一個新的數組
    ensureCapacityInternal(size + 1); 
    //賦值
    elementData[size++] = e;
    return true;
}

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

/**
 * 若數組是經過無參構造器的方式實例化的話,返回的minCapacity爲10,最後會經過grow方法複製生成一個大小爲10的數組
 * 若數組是經過有參構造器的方式實例化的話,返回的minCapacity爲當前要操做的數組下標,不建議聲明小於10的數組空間,由於這樣前幾回add都要去擴容複製生成一個新的數組
 */
private void ensureExplicitCapacity(int minCapacity) {
    modCount++;

    // overflow-conscious code
    if (minCapacity - elementData.length > 0)
    grow(minCapacity);
}

//擴容大小:原數組大小 + 原數組大小/2
private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    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);
}
  • 其它說明併發

    1. 初始化ArrayList時,不建議聲明小於10的容量,由於這樣前幾回add都要去擴容複製生成一個新的數組
    2. Arrays.copyOf(T[] original, int newLength):該方法會建立一個新的數組

remove

  • 流程圖

clipboard.png

  • 源碼解析
public E remove(int index) {
    //檢查index是否 >= size,若大於則報數組越界異常
    rangeCheck(index);

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

    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

    return oldValue;
}
  • 其它說明this

    1. System.arraycopy - 淺複製
public static void arraycopy(
                             Object src,  //源數組
                             int srcPos,  //源數組要複製的起始位置
                             Object dest, //目標數組
                             int destPos, //目的數組放置的起始位置
                             int length   //複製長度
                             )

4、補充

  • ArrayList是線程不安全的,表如今多線程下add和remove可能會發生數組越界
  • 不要在foreach循環裏進行元素的remove/add操做。remove元素請使用Iterator方式,若是併發操做,須要對Iterator對象加鎖
相關文章
相關標籤/搜索