ArrayList
1. 概述
ArrayList 是 List 的一個實現, 其底層使用數組來存儲元素, 且支持數組動態擴容
因爲底層使用數組, 所以 ArrayList 的查找較快, 增加和刪除較慢。
2. 類
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
......
}
繼承實現關係圖
-
繼承 AbstractList 抽象類
說明其是一個List,且實現了List相關的方法。 -
實現 RandomAccess 接口
RandomAccess 是一個標記接口, 用來標記支持快速訪問的類。RandomAccess 接口主要用在 Collections 工具類上, Collections 中的一些靜態方法在操作集合遍歷元素時, 如果該集合實現了RandomAccess 接口則使用 for 循環遍歷, 如果沒有則使用迭代器遍歷。 -
實現 Clone 接口
實現了clone()方法。 -
實現 Serializable 接口
標記接口,表明 ArrayList 可以被序列化,並且加入了 serialVersionUID 字段標識版本。 -
實現 List 接口
AbstractList 已經實現了 List 接口,此處卻又實現了一次是因爲,如果不這樣做的話在使用代理時會報異常,具體參考附錄鏈接。
3. 屬性
// 序列化版本號
private static final long serialVersionUID = 8683452581122892189L;
// 默認容量
private static final int DEFAULT_CAPACITY = 10;
// 空數組
private static final Object[] EMPTY_ELEMENTDATA = {};
// 默認容量空數組
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
// 元素數組
transient Object[] elementData;
// 集合的元素個數, 不一定等於elementData.length
private int size;
4. 方法
構造方法
構造方法共有三個
- 無參構造
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
該方法將默認的空數組賦給 elementData , 在調用 add 方法時會爲其分配一個默認長度爲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);
}
}
- 參數爲Collection集合的構造方法
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// toArray() 方法有可能不會返回Object[]對象
if (elementData.getClass() != Object[].class)
// 使用Native方法 Arrays.copy()
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// 數組長度爲0,爲其分配空數組
this.elementData = EMPTY_ELEMENTDATA;
}
}
add()
public boolean add(E e) {
// 確保數組容量夠用, size是元素個數
ensureCapacityInternal(size + 1); // Increments modCount!!
// 將元素加在末尾
elementData[size++] = e;
return true;
}
進入 ensureCapacityInternal (int minCapacity)
private void ensureCapacityInternal(int minCapacity) {
// 通過 calculateCapacity 計算容量, 默認容量則返回10, 否則返回minCapacity, 在當做參數傳遞,
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
進入ensureExplicitCapacity(int minCapacity)
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// 需要的容量大於元素數組的長度則調用grow(minCapacity)方法進行擴容
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
進入grow(int minCapacity)
private void grow(int minCapacity) {
int oldCapacity = elementData.length;
// 新容量爲舊容量的1.5倍, >> 向右移位運算, 相當於 / 2
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 如果新容量還是小於最小需要的容量
if (newCapacity - minCapacity < 0)
// 那麼直接將需要的容量作爲新容量
newCapacity = minCapacity;
// 如果新容量大於了數組大小的最大值, 那麼就將最大值賦給它
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// 調用 Native 方法進行數組拷貝
elementData = Arrays.copyOf(elementData, newCapacity);
// 擴容完成, 返回add方法添加元素
}
add(index)
public void add(int index, E element) {
// 範圍檢查 index要在 0 到 size 之間, 否則拋出異常
rangeCheckForAdd(index);
// 同上add()方法一樣, 確保數組大小夠用, 不夠擴容
ensureCapacityInternal(size + 1); // Increments modCount!!
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}
remove()
public E remove(int index) {
// 檢查index 在 0 到 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;
}
remove(Object)
public boolean remove(Object o) {
// 判空處理, 防止空指針異常
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
// index後的元素向前移動 同 remove(int)中的邏輯
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
// 對象的話調用equals()
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
removeAll()
public boolean removeAll(Collection<?> c) {
Objects.requireNonNull(c);
return batchRemove(c, false);
}
retainAll()
public boolean retainAll(Collection<?> c) {
Objects.requireNonNull(c);
return batchRemove(c, true);
}
batchRemove()
removeAll() 和 retainAll() 的邏輯類似, 所以都同一由同一個方法batchRemove()實現, 只是在傳參的時候, removeAll() 傳 false表示不保留相同的元素, retainAll()傳true表示只保留相同的元素
private boolean batchRemove(Collection<?> c, boolean complement) {
final Object[] elementData = this.elementData;
int r = 0, w = 0;
boolean modified = false;
try {
// 遍歷 elementData
for (; r < size; r++)
// complement 爲 false 表示 c 不包含的複製保存, c 包含的不復制 true 則相反
if (c.contains(elementData[r]) == complement)
elementData[w++] = elementData[r];
} finally {
// 如果 contains 方法拋異常, 則執行finally, r != size 表示還沒複製完成
if (r != size) {
// 繼續複製剩下的元素
System.arraycopy(elementData, r,
elementData, w,
size - r);
w += size - r;
}
// 發生了刪除, 元素數量變少, 需要把末尾的重複對象引用釋放掉, 以便GC回收
if (w != size) {
// clear to let GC do its work
for (int i = w; i < size; i++)
elementData[i] = null;
modCount += size - w;
// 更新size大小
size = w;
modified = true;
}
}
return modified;
}
indexOf()
public int indexOf(Object o) {
// 判空, 防止equals空指針
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;
}
get(int)
public E get(int index) {
rangeCheck(index);
return elementData(index);
}
set(int, E)
public E set(int index, E element) {
rangeCheck(index);
E oldValue = elementData(index);
elementData[index] = element;
return oldValue;
}
elementData(int)
E elementData(int index) {
return (E) elementData[index];
}