ArrayList源碼分析
1.繼承結構
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
說明:ArrayList繼承AbstractList抽象父類,實作了List接口(規定了List的操作規範)、RandomAccess(可随機通路)、Cloneable(可拷貝)、Serializable(可序列化)。
2.屬性:
//版本号
private static final long serialVersionUID = L;
/**
* 預設容量
*/
private static final int DEFAULT_CAPACITY = ;
/**
* 空對象數組
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
/**
* 預設空數組
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
* 元素數組
*/
transient Object[] elementData; // non-private to simplify nested class access
/**
* 容量
*/
private int size;
transient 關鍵字
- Java的Serializable提供了一種序列化對象執行個體的機制。當序列化對象時,可能有一個特殊的對象資料成員,我們不想用Serializable機制來儲存它。為了在一個特定對象的一個域上關閉Serializable,可以在這個域前加上關鍵字transient。
- transient是Java語言的關鍵字,用來表示一個域不是該對象序列化的一部分。當一個對象被序列化的時候,transient型變量的值不包括在序列化的表示中,然而非transient型的變量是被包括進去的。
3.構造方法:
- 無參的構造方法。
/**
* 說明了預設會給10的大小,是以說一開始arrayList的容量是10.
* ArrayList中儲存資料的其實就是一個數組,這個數組就是elementData
*/
public ArrayList() {
//設定元素數組為空
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
有參數的構造器:
/**
* 傳入一個初始化大小的一個參數。
*/
public ArrayList(int initialCapacity) {
if (initialCapacity > ) {
//如果大于0将自定義的容量作為初始化elementData的大小
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == ) {
//如果等于0将将數組指派為空對象數組
this.elementData = EMPTY_ELEMENTDATA;
} else {
//判斷如果自定義大小的容量小于0,則報下面這個非法資料異常
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
有參數的構造方法:
//集合參數構造函數
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray(); // 轉化為數組
if ((size = elementData.length) != ) {// 參數為非空集合
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)//// 是否成功轉化為Object類型數組
elementData = Arrays.copyOf(elementData, size, Object[].class);// 不為Object數組的話就進行複制
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
核心方法:
1.add函數:
//添加元素
public boolean add(E e) {
//(ensureCapacityInternal)為確定elementData數組有合适的大小,是否需要擴容
ensureCapacityInternal(size + ); // Increments modCount!!
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
//如果建立ArrayList時用的是無參構造器,則第一次插入時會進行一次擴容并且擴到預設數組大小10
//然而如果是使用帶有容量參數的構造器且initialCapacity=0時,則不會進行這一步,直接擴充數組容量為minCapacity
//這就導緻一個結果,擴容之後帶參數的構造器的數組length為1,而預設的為10
//是以,帶容量參數的初始化時注意自己需要的大小
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
// 超出了數組可容納的長度,則進行動态擴充
if (minCapacity - elementData.length > )
grow(minCapacity);
}
//grow函數會對數組進行擴容
private void grow(int minCapacity) {
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> );
if (newCapacity - minCapacity < )
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > )
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity);
}
容量的拓展将導緻數組元素的複制,多次拓展容量将執行多次整個數組内容的複制。若提前能大緻判斷list的長度,調用ensureCapacity調整容量,将有效的提高運作速度。
可以了解提前配置設定好空間可以提高運作速度,但是測試發現提高的并不是很大,而且若list原本資料量就不會很大效果将更不明顯。
set函數:
public E set(int index, E element) {
rangeCheck(index);//檢查是否越界
E oldValue = elementData(index);//拿到原來的值
elementData[index] = element;//賦新值
return oldValue;//傳回原來的值。
}
ArrayList有其特殊的應用場景,與LinkedList相對應。其優點是随機讀取,缺點是插入元素時需要移動大量元素,效率不太高。