ArrayList是java中使用頻率非常高的一個集合類,它的底層採用數組來實現,本文主要來探究一下其源碼,幫助記憶和理解。 ...
摘要
ArrayList 是Java中常用的一個集合類,其繼承自AbstractList並實現了List
構造器
ArrayList 提供了三個構造器,分別是
含參構造器-1
// 含參構造器-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);
}
}
含參構造器-2
// 含參構造器-2
// 參數含義:其他的集合類型轉為ArrayList
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;
}
}
無參構造器
// 無參構造器
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
成員變數
// 預設的表容量
private static final int DEFAULT_CAPACITY = 10;
// 構造參數為 0 的時候,預設都指向該數組
private static final Object[] EMPTY_ELEMENTDATA = {};
// 無參構造時預設指向該數組
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
// 實際存放數據的數組
transient Object[] elementData;
// 表大小
private int size;
// 修改次數 Modify Count (定義在AbstractList中) 【劃重點】
protected transient int modCount = 0;
關於這兩個空數和構造器,參考如下代碼
ArrayList a1 = new ArrayList(0);
ArrayList a2 = new ArrayList();
ArrayList a3 = new ArrayList();
ArrayList a4 = new ArrayList(0);
Field field = ArrayList.class.getDeclaredField("elementData");
field.setAccessible(true);
System.out.println(field.get(a1) == field.get(a2));
System.out.println(field.get(a2) == field.get(a3));
System.out.println(field.get(a1) == field.get(a4));
以上代碼將會輸出如下結果
false # a1.elementData ≠ a2.elementData
true # a2.elementData = a3.elementData
true # a1.elementData = a4.elementData
內部類
// 迭代器實現類,實現了Iterator介面,可以使用增強的for迴圈
private class Itr implements Iterator<E>{}
// 需要註意的是:ListIterator介面繼承於Iterator介面
// ListIterator 和 Iterator最大的區別在於:Iterator單向移動,而ListIterator可以雙向移動並且可以增加、設置元素
// forEachRemaining 方法都是向後迭代的
private class ListItr extends Itr implements ListIterator<E>{}
// 為sublist()方法準備的內部類
private class SubList extends AbstractList<E> implements RandomAccess]{}
// 為多核應用開發所準備的Spliterator
static final class ArrayListSpliterator<E> implements Spliterator<E>{}
常用方法
擴容機制
ArrayList的擴容由以下幾個方法來實現。要明確的是,ArrayList的容量實際上就是其存放數據的elementData數組的長度,每一次自動的擴容都是由當前表的大小和elementData的長度做對比後而決定的。
// 供使用者調用的容量初始化方法,在大量增加新數據的情況下,預先確定足夠的容量可以減少時間開支(因為會因為表不夠大而頻繁的擴容)
public void ensureCapacity(int minCapacity) {
int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
// any size if not default element table
? 0
// larger than default for default empty table. It's already
// supposed to be at default size.
: DEFAULT_CAPACITY;
// 最小能保證表容量為DEFAULT_CAPACITY(10)
if (minCapacity > minExpand) {
ensureExplicitCapacity(minCapacity);
}
}
// 這個方法供內部調用,也就是在add和addAll里使用的。
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
// 按最大的算,此處也可以看出來,容量最小也是DEFAULT_CAPACITY(10)
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
// 不夠大就擴容
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
/**
* The maximum size of array to allocate.
* Some VMs reserve some header words in an array.
* Attempts to allocate larger arrays may result in
* OutOfMemoryError: Requested array size exceeds VM limit
*/
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
/**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
* 實際的擴容方法
* @param minCapacity the desired minimum capacity
*/
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1); // 擴容實際最小擴的是1.5倍
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity); // 最大也只能能是MAX_ARRAY_SIZE(有可能是Integer.MAX_VALUE)
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
add
- 預設增加到最後一個元素後面
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
在指定位置後面插入
public void add(int index, E element) { rangeCheckForAdd(index); ensureCapacityInternal(size + 1); // Increments modCount!! System.arraycopy(elementData, index, elementData, index + 1, size - index); elementData[index] = element; size++; }
addAll
- 預設增加到最後一個元素後面
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;
}
- 在指定位置後面插入
public boolean addAll(int index, Collection<? extends E> c) {
rangeCheckForAdd(index);
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityInternal(size + numNew); // Increments modCount,同時確認是否擴容
int numMoved = size - index;
if (numMoved > 0)
System.arraycopy(elementData, index, elementData, index + numNew,
numMoved);
System.arraycopy(a, 0, elementData, index, numNew);
size += numNew;
return numNew != 0;
}
remove
- 按下標
public E remove(int index) {
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;
}
按元素
public boolean remove(Object o) { 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; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // clear to let GC do its work,防止記憶體泄露 }
set
- 指定位置
// 插入新值,返回舊值
public E set(int index, E element) {
rangeCheck(index);
E oldValue = elementData(index);
elementData[index] = element;
return oldValue;
}
get
- 指定位置
public E get(int index) {
rangeCheck(index);
return elementData(index);
}
clear
public void clear() {
modCount++;
// 這裡不能簡單的把size置為0就完事,要確定本表對每一個元素不再有引用關係,避免記憶體泄漏
// clear to let GC do its work
for (int i = 0; i < size; i++)
elementData[i] = null;
size = 0;
}
trimToSize
一般來說,表的大小要小於等於表的容量,而在記憶體緊張的時候,可能會用到該方法來使表的容量縮小至表的大小一樣大。
public void trimToSize() {
modCount++;
// size 只會 ≤ elementData.length,而等於的時候該方法的目的已經達到就不用做任何事了
if (size < elementData.length) {
elementData = (size == 0)
? EMPTY_ELEMENTDATA
: Arrays.copyOf(elementData, size);
}
}
indexOf
public int indexOf(Object o) {
// 註意這裡區分了 o 是否為 null
// 為null的情況很好理解,因為 null 的含義是確認的
// 但是不為空即是一個對象的話,就需要用到equals方法,所以一般的類會重寫equals方法
// Object的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;
}
lastIndexOf
這個方法是與indexOf
對應的一個方法,indexOf
的實現是正序查找,而本方法是逆序查找
public int lastIndexOf(Object o) {
if (o == null) {
for (int i = size-1; i >= 0; i--)
if (elementData[i]==null)
return i;
} else {
for (int i = size-1; i >= 0; i--)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
contains
這個方法的內部實現是依靠indexOf
方法來實現的
public boolean contains(Object o) {
return indexOf(o) >= 0;
}
sublist
public List<E> subList(int fromIndex, int toIndex) {
subListRangeCheck(fromIndex, toIndex, size);
// 這裡就用到了前面列出的SubList內部類
// 需要註意的是:由sublist方法返回的List,對其操作時會在原List上生效,即它們是同一個元素
return new SubList(this, 0, fromIndex, toIndex);
}
補充方法
此外有四個補充的方法需要註意,這四個方法的參數都是函數式介面的實現類,即可以使用λ表達式
forEach
顧名思義,作用於每一個元素的方法
public void forEach(Consumer<? super E> action) {
Objects.requireNonNull(action);
final int expectedModCount = modCount;
@SuppressWarnings("unchecked")
final E[] elementData = (E[]) this.elementData;
final int size = this.size;
// 正向遍歷
for (int i=0; modCount == expectedModCount && i < size; i++) {
// accept的原型為: void accept(T t); 即一個無返回值的函數,也是需要在λ表達式里表示的內容
action.accept(elementData[i]);
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}
removeIf
public boolean removeIf(Predicate<? super E> filter) {
Objects.requireNonNull(filter);
// figure out which elements are to be removed
// any exception thrown from the filter predicate at this stage
// will leave the collection unmodified
int removeCount = 0;
final BitSet removeSet = new BitSet(size);
final int expectedModCount = modCount;
final int size = this.size;
for (int i=0; modCount == expectedModCount && i < size; i++) {
@SuppressWarnings("unchecked")
final E element = (E) elementData[i];
// test的原型為: boolean test(T t); 返回布爾值,在這裡也能看出來,當返回的值為true時,才進行代碼塊的操作
if (filter.test(element)) {
removeSet.set(i);
removeCount++;
}
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
// shift surviving elements left over the spaces left by removed elements
final boolean anyToRemove = removeCount > 0;
if (anyToRemove) {
final int newSize = size - removeCount;
for (int i=0, j=0; (i < size) && (j < newSize); i++, j++) {
i = removeSet.nextClearBit(i);
elementData[j] = elementData[i];
}
for (int k=newSize; k < size; k++) {
elementData[k] = null; // Let gc do its work
}
this.size = newSize;
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
modCount++;
}
return anyToRemove;
}
replaceAll
public void replaceAll(UnaryOperator<E> operator) {
// UnaryOperator 一元運算符
Objects.requireNonNull(operator);
final int expectedModCount = modCount;
final int size = this.size;
for (int i=0; modCount == expectedModCount && i < size; i++) {
// UnaryOperator<T> 繼承自 Function<T,T(R)>
// 其apply 的原型為: R apply(T t);
// BinaryOperator<T> 繼承自 BiFunction<T,T(U),T(R)>
// 其apply方法原型為: R apply(T t, U u);
elementData[i] = operator.apply((E) elementData[i]);
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
modCount++;
}
sort
這裡的排序是藉助於Arrays這個工具類的sort方法來實現的,這裡僅作參考
public void sort(Comparator<? super E> c) {
final int expectedModCount = modCount;
Arrays.sort((E[]) elementData, 0, size, c);
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
modCount++;
}