Java之集合 - ArrayList源碼分析

一、簡介

上圖爲ArrayList的繼承樹,可看出實現了四個接口,分別介紹一下:

  • Serializable:是一個空接口,實現了該接口的類可序列化和反序列化
  • Cloneable:是一個空接口,實現該接口的類覆蓋了clone()方法,表明該類的實例對象能被克隆
  • RandomAccess:是一個空接口,表明該類的實例對象支持隨機訪問
  • List:表明該類是一個列表,具有增加、刪除、修改、遍歷等功能

 

二、源碼分析

1. ArrayList的屬性

// 默認初始化容量爲10
private static final int DEFAULT_CAPACITY = 10; 
// 空數組實例
private static final Object[] EMPTY_ELEMENTDATA = {}; 
// 當使用默認初始化容量時創建的空數組實例
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
// 存放元素的數組
// 當 elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA 
// 將第一個元素存入ArrayList時該數組會擴容至容量爲10
transient Object[] elementData;
// ArrayList的實際大小,即存放的元素數量
private int size;
// ArrayList允許存放的最大元素數
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

2. 構造方法

// 默認構造函數,使用默認初始化容量10,存放元素的數組指向一個空數組,
public ArrayList() {
	this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

// 傳入一個初始化容量值,將存放元素的數組大小設置爲該值
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(Collection<? extends E> c) {
	elementData = c.toArray();
	if ((size = elementData.length) != 0) { 
		// 集合非空時則將集合的元素複製至數組
		if (elementData.getClass() != Object[].class)
			elementData = Arrays.copyOf(elementData, size, Object[].class);
	} else {
		// 傳入的集合爲空時指向一個空數組
		this.elementData = EMPTY_ELEMENTDATA;
	}
}

3. 增加元素

// 將元素添加到數組末尾
public boolean add(E e) {
	ensureCapacityInternal(size + 1);  // 判斷是否需要擴容,後面詳細講
	elementData[size++] = e;
	return true;
}

// 將元素添加到指定位置
public void add(int index, E element) {
	rangeCheckForAdd(index); // 檢查是否越界

	ensureCapacityInternal(size + 1); 
	System.arraycopy(elementData, index, elementData, index + 1,
					 size - index); // 將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;
}

// 將集合元素添加至指定位置
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;
}

5. 刪除元素

// 將指定位置的元素刪除
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; 

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

// 刪除指定範圍的元素
protected void removeRange(int fromIndex, int toIndex) {
	modCount++;
	int numMoved = size - toIndex;
	System.arraycopy(elementData, toIndex, elementData, fromIndex,
					 numMoved);

	int newSize = size - (toIndex-fromIndex);
	for (int i = newSize; i < size; i++) {
		elementData[i] = null;
	}
	size = newSize;
}

// 刪除數組中與集合相等的元素
public boolean removeAll(Collection<?> c) {
	Objects.requireNonNull(c); // 檢查集合是否爲null
	return batchRemove(c, false);
}

// 按指定條件刪除元素
@Override
public boolean removeIf(Predicate<? super E> filter) {
	Objects.requireNonNull(filter);
	
	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];
		if (filter.test(element)) { // 檢驗元素是否符合刪除條件
			removeSet.set(i); // 將符合條件的元素在removeSet中對應的位置置true
			removeCount++;
		}
	}
	if (modCount != expectedModCount) {
		throw new ConcurrentModificationException();
	}

	final boolean anyToRemove = removeCount > 0; // 是否有元素被刪除
	if (anyToRemove) { // 若爲true則將數組中符合條件的元素刪除
		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;
		}
		this.size = newSize;
		if (modCount != expectedModCount) {
			throw new ConcurrentModificationException();
		}
		modCount++;
	}

	return anyToRemove;
}


// 刪除所有元素
public void clear() {
	modCount++;

	for (int i = 0; i < size; i++)
		elementData[i] = null;

	size = 0;
}

6. 修改元素

// 修改指定位置的元素,並返回舊值
public E set(int index, E element) {
	rangeCheck(index);

	E oldValue = elementData(index);
	elementData[index] = element;
	return oldValue;
}

7. 獲取元素

// 獲取指定位置的元素
public E get(int index) {
	rangeCheck(index);

	return elementData(index);
}

E elementData(int index) {
	return (E) elementData[index];
}

8. 擴容機制

// 當嘗試增加一個元素時,會調用該函數
private void ensureCapacityInternal(int minCapacity) {
	ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}

// 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) {
	modCount++;

	// 若增加元素後數組大小大於原數組大小則需要擴容
	if (minCapacity - elementData.length > 0)
		grow(minCapacity);
}


// 擴容至原數組大小的1.5倍
private void grow(int minCapacity) {
	int oldCapacity = elementData.length;
	int newCapacity = oldCapacity + (oldCapacity >> 1);
	if (newCapacity - minCapacity < 0)
		newCapacity = minCapacity;
	if (newCapacity - MAX_ARRAY_SIZE > 0)
		newCapacity = hugeCapacity(minCapacity);
	elementData = Arrays.copyOf(elementData, newCapacity);
}

private static int hugeCapacity(int minCapacity) {
	if (minCapacity < 0) // 上溢
		throw new OutOfMemoryError();
	return (minCapacity > MAX_ARRAY_SIZE) ?
		Integer.MAX_VALUE :
		MAX_ARRAY_SIZE;
}
  1. 計算增加元素後元素的個數:當增加元素時,會先調用方法計算增加元素後元素的個數,分爲兩種情況,若數組爲空則取初始化容量和增加元素後元素個數的最大值,否則直接返回增加元素後元素個數
  2. 判斷是否擴容:根據返回值,如果大於當前數組的容量則需要擴容
  3. 擴容:新的容量爲原來的1.5倍,若該值小於元素個數則新容量更改爲元素個數,若大於MAX_ARRAY_SIZE則取Integer允許的最大值和MAX_ARRAY_SIZE的最大值,若小於0即上溢,拋出異常
  4. 複製元素至擴容後的數組
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章