ArryaList源碼淺析
一 .繼承關系
ArrayList是java中常用的集合架構之一,其内部資料存儲為數組形式,其繼承關系如上圖所示。
二.屬性與方法
屬性
-
序列化版本ID,用于反序列化進行版本比較,若反序列化時UID不一緻将會抛出java.io.InvalidClassException異常。private static final long serialVersionUID = 8683452581122892189L;
-
用于空清單的共享空對象數組,避免每次執行個體化時重新申請。private static final Object[] EMPTY_ELEMENTDATA = {};
-
同樣也是用于空清單的共享空對象數組,用于無參構造,和EMPTY_ELEMENTDATA的具體差別見注意事項。private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
-
用于存放該清單的資料。transient Object[] elementData;
-
該清單中元素的個數(指的是元素的個數,而非elementData數組的大小)。private int size;
-
預設的初始化數組大小。private static final int DEFAULT_CAPACITY = 10;
-
數組申請的最大大小,為什麼會是Integer.MAX_VALUE - 8?這是因為有些虛拟機會在數組頭部占用一定的空間,如果嘗試申請Integer.MAX_VALUE大小的數組,可能會導緻OutOfMemoryError: Requested array size exceeds VM limit。private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
方法
構造方法
-
有參構造方法,建立一個指定數組大小的空清單,如果initialCapacity為0,其elementData=EMPTY_ELEMENTDATA。public ArrayList(int initialCapacity);
-
無參構造方法,elementData=DEFAULTCAPACITY_EMPTY_ELEMENTDATA。public ArrayList();
-
有參構造方法,将傳入的集合轉換為數組存入elementData中,若集合為空,elementData=EMPTY_ELEMENTDATA。public ArrayList(Collection<? extends E> c);
清單核心方法
-
public void ensureCapacity(int minCapacity);
ArryaList的擴容方法,将對象數組的大小擴容為至少滿足minCapacity大小的程度。
擴容規則:
- 計算minExpand,若elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA時為0,否則為DEFAULT_CAPACITY = 10。
- 若minCapacity <= minExpand時,不進行擴容。否則繼續進行擴容
- 計算minCapacity是否大于目前數組大小,大于時才進行擴容,防止資料丢失。
- 計算newCapacity(原數組大小的1.5倍)
- newCapacity取newCapacity與minCapacity的較大者
- 判斷newCapacity是否大于MAX_ARRAY_SIZE。大于時若minCapacity < 0 抛出OutOfMemoryError異常,minCapacity > MAX_ARRAY_SIZE時newCapacity取Integer.MAX_VALUE,否則取MAX_ARRAY_SIZE。
- 根據newCapacity建立新數組,并将原數組資料進行拷貝。
-
傳回size的值,即清單中元素的個數。public int size();
-
判斷清單是否為空,即size == 0?public boolean isEmpty();
-
public boolean contains(Object o);
查詢清單中是否包含對象o,若不包含對象o,傳回false。
注意:這裡的o可以為null,此時比較直接使用==比較符,若o為對象,則調用該對象的equals方法。(内部實作為indexOf(Object o))。
-
public int indexOf(Object o);
從頭開始查詢清單,傳回對象o的數組下表,未查詢到時傳回-1。
注意:這裡的o可以為null,此時比較直接使用==比較符,若o為對象,則調用該對象的equals方法。
-
從末尾開始查詢清單,傳回對象o的數組下表,未查詢到時傳回-1。public int lastIndexOf(Object o);
-
根據索引值擷取指定位置的資料。public E get(int index);
-
根據索引值重新設定指定位置的資料,傳回舊值。public E set(int index, E element);
-
判斷數組是否能容納size+1個元素,不滿足則先進行擴容,最後添加元素至數組末尾。public boolean add(E e);
-
判斷數組是否能容納size+1個元素,不滿足則先進行擴容,最後添加元素至指定的索引位置。public void add(int index, E element);
-
删除指定索引位置的資料,傳回删除元素的值。public E remove(int index);
-
删除指定的元素,o可以為null,從數組頭部開始配置,删除比對到的第一個元素。public boolean remove(Object o);
-
将數組所有元素置為null,size=0。public void clear();
-
public boolean addAll(Collection<? extends E> c);
功能方法
-
調整對象數組elementData的大小與size的值一緻,若size==0時将elementData的引用指向EMPTY_ELEMENTDATA。該方法主要用于減少清單的大小,釋放存儲空間。public void trimToSize();
-
Object.clone()方法的實作,淺拷貝。public Object clone();
-
傳回該清單元素的一個新數組,注意同樣是淺拷貝。public Object[] toArray();
-
public <T> T[] toArray(T[] a);
将清單中元素複制到數組a中。
注意:當a.length<list.size時,原數組不會有任何變化,a.length=list.size時,原數組元素和清單中元素一緻,a.length>list.size, a[0]~a[size-1]為清單中元素,a[size]置為null。
-
将指定集合添加至數組末尾。public boolean addAll(Collection<? extends E> c);
-
将指定集合添加至指定索引處。public boolean addAll(int index, Collection<? extends E> c);
-
将既存在原清單中又存在集合c中的元素移除出清單,即兩集合的差集。public boolean removeAll(Collection<?> c);
-
将既存在原清單中又存在集合c中的元素保留,即兩集合的交集。public boolean retainAll(Collection<?> c);
-
public List<E> subList(int fromIndex, int toIndex);
根據指定的索引傳回一個新的清單。
注意:該清單不是ArryaList,而是ArrayList的一個内部類SubList!
疊代器相關方法
-
從指定索引處傳回疊代器ListItrpublic ListIterator<E> listIterator(int index);
-
從數組起始處傳回疊代器ListItrpublic ListIterator<E> listIterator();
-
傳回疊代器Itrpublic Iterator<E> iterator();
三.注意事項
-
EMPTY_ELEMENTDATA與DEFAULTCAPACITY_EMPTY_ELEMENTDATA
ArryaList的無參構造函數會預設elementData為DEFAULTCAPACITY_EMPTY_ELEMENTDATA,在擴容時若需求大小小于DEFAULT_CAPACITY(10)時,擴容為10,防止在清單小的時候頻繁擴容。
-
ArrayList支援序列化為什麼elementData被transient修飾?
在writeObject和readObject方法中進行了處理,隻序列化實際存儲的元素和size,而不是整個elementData數組。因為elementData數組的大小比size大,不需要序列化大于size的這部分數組。
- 疊代器ListItr和Itr的差別