ArrayList 特點+源碼分析記錄

包含內容

  1. 特點
  2. 增刪改查源碼分析

特點

  1. 按照插入順序來保存元素,可以利用下標來查找值
  2. 按照下標訪問元素最快O(1)
  3. 在中間插入元素很慢 & 刪除元素很慢
  4. 允許數據null
  5. 線程不安全
  6. 底層是數組,默認數組長度爲10,擴容先進行1.5倍擴容,不夠直接使用需要長度爲容量

####1. 構造方法

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

public ArrayList() {
	// 默認是空數組
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

// 把另一個集合轉成數組初始化數組
public ArrayList(Collection<? extends E> c) {
    elementData = c.toArray();
    if ((size = elementData.length) != 0) {
        // c.toArray might (incorrectly) not return Object[] (see 6260652)
        if (elementData.getClass() != Object[].class)
            elementData = Arrays.copyOf(elementData, size, Object[].class);
    } else {
        // replace with empty array.
        this.elementData = EMPTY_ELEMENTDATA;
    }
}

####2. 增

 public boolean add(E e) {
	// 判斷是否需要擴容 詳見2.1
    ensureCapacityInternal(size + 1);  // Increments modCount!!
	// 順序添加數據
    elementData[size++] = e;
    return true;
}

public void add(int index, E element) {
	// 檢查添加的下標是否越界 ,詳見2.2
    rangeCheckForAdd(index);
	// 檢測是否需要擴容
    ensureCapacityInternal(size + 1);  // Increments modCount!!
	// 講index後的數據都向後移動1個位置 , 詳見2.3
    System.arraycopy(elementData, index, elementData, index + 1,size - index);
	// 賦值
    elementData[index] = element;
	// 數據長度++
    size++;
}

public boolean addAll(Collection<? extends E> c) {
    Object[] a = c.toArray();
    int numNew = a.length;
    ensureCapacityInternal(size + numNew);  // Increments modCount
    System.arraycopy(a, 0, elementData, size, numNew);
    size += numNew;
    return numNew != 0;
}
2.1 擴容
private void ensureCapacityInternal(int minCapacity) {
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}

private void ensureExplicitCapacity(int minCapacity) {
    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)
		// 第二步 : 如果增加1.5倍後還是不夠長就直接使用需要長度
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    // minCapacity is usually close to size, so this is a win:
	// 通過System.arraycopy 擴容
    elementData = Arrays.copyOf(elementData, newCapacity);
}
2.2 檢測是否越界
private void rangeCheckForAdd(int index) {
	// 如果下標大於內容長度 || 下標<0 拋出錯誤
    if (index > size || index < 0)
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
2.3 添加數據後,數據位置向後移動
public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)

方法解釋 : 複製指定的源數組的數組,在指定的位置開始,到目標數組的指定位置

參數解釋:

Object src : 原數組
int srcPos : 從元數據的起始位置開始
Object dest : 目標數組
int destPos : 目標數組的開始起始位置
int length : 要copy的數組的長度

// 把elementData數組從index開始複製到elementData數組index+1位置,複製的數據長度爲size - index , 所以下標index就空出來了 , 爲後面賦值做準備
System.arraycopy(elementData, index, elementData, index + 1,size - index);

3. 刪除

public E remove(int index) {
	// 檢測index > size , 是就拋出異常
    rangeCheck(index);

    modCount++;
	// 找到數據
    E oldValue = elementData(index);
	// 判斷是否刪除的是最後一個
    int numMoved = size - index - 1;
	// 如果不是最後一個就把刪除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;
}


public boolean remove(Object o) {
	// 遍歷數組 , 找到o所在的下標 , 進行刪除fastremove
    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) {
    modCount++;
	// 判斷是否是最後一個
    int numMoved = size - index - 1;
	// 刪除的不是最後一個就把刪除下標後的數據全部前移1個位置
    if (numMoved > 0)
        System.arraycopy(elementData, index+1, elementData, index,
                         numMoved);
    elementData[--size] = null; // clear to let GC do its work
}

4. 改

public E set(int index, E element) {
	// 檢測下標是否越界
    rangeCheck(index);
	// 取出舊值
    E oldValue = elementData(index);
	// 設置新值
    elementData[index] = element;
    return oldValue;
}

5. 查

public E get(int index) {
	// 檢測是否越界
    rangeCheck(index);
	// 返回下標下的數據
    return elementData(index);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章