本章分析List系列中的ArrayList,有些與PriorityQueue類似,比如底層同樣採取數組存儲元素,也涉及到擴容操作等;也有不同之處,比如PriorityQueue不允許存入的元素爲null,而ArrayList允許將null元素存放其中。
一、 類實現/繼承體系結構
爲了對整個List實現/繼承體系有個全貌,先將體系結構圖畫出來:
二、 關鍵數據成員
(1)存儲結構
transient Object[]elementData; // non-private to simplify nested class access;
以數組作爲底層存儲結構,存放ArrayList鏈表中的元素
數組elementData的默認初始化大小(DEFAULT_CAPACITY)是10。
(2)數組存放的元素個數
private int size;
三、 構造函數
ArrayList提供了多種形式的構造函數,在此不一一列舉,就參數來說,主要包括,數組鏈表(elementData)初始化大小(initialCapacity)值、其他集合
這裏要講下以下幾個構造函數:
publicArrayList (Collection<? extends E> c):利用另一個集合初始化ArrayList,要求就是負責初始化集合中的元素類型是E或者是E的子類。
四、 一些鏈表操作
(1) void trimToSize():將ArrayList的存儲空間壓縮到size大小,將空閒空間還給系統
做法就是Arrays.copyOf(elementData, size)新生成一個數組,賦值給elementData;
(2) void sort(Comparator<? super E> c):對鏈表進行排序,調用了Arrays.sort接口
Arrays.sort((E[])elementData, 0, size, c);
這裏有一點,因爲ArrayList接口都不是線程安全的,在一個線程操作鏈表時,並不能防止其他線程也在操作鏈表,有可能在排序時,其他線程已經修改了鏈表,修改有可能導致排序結果不準確,所以,這時就需要拋出異常:
public void sort(Comparator<?super E> c) {
final int expectedModCount = modCount;
Arrays.sort((E[]) elementData, 0, size, c);
if (modCount != expectedModCount) {
throw newConcurrentModificationException();
}
modCount++;
}
五、 增
(1) boolean addAll(Collection<? extends E> c):將容器c中元素添加到ArrayList的末尾
首先檢查容量capacity,然後執行拷貝
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityInternal(size +numNew); // Increments modCount
System.arraycopy(a, 0, elementData,size, numNew);
size += numNew;
System.arraycopy參數含義:
第一個參數:數據來源數組;
第二個參數:數據來源數組的起始拷貝索引index;
第三個參數:數據目標數組;
第四個參數:數據目標數組起始拷貝索引index;
第五個參數:拷貝元素的個數;
(2) boolean addAll(int index, Collection<?extends E> c):將容器c中元素添加到ArrayList中,添加的起始位置是在index處
如果index不是數組末尾,就涉及到兩次拷貝:
if (size - index > 0)
System.arraycopy(elementData,index, elementData, index+numNew, numMoved);
System.arraycopy(a,0, elementData, index, numNew);
六、 刪
(1) E remove(int index):刪除位於index位置的元素
不可避免的,會將數組elementData 在index之後元素前移一個位置,複雜度O(n)
System.arraycopy(elementData,index+1, elementData, index, numMoved);
(2) boolean removeAll(Collection<?> c):刪除ArrayList中的集合c中的元素,即求交集
這裏使用了一個叫做batchRemove的私有函數:
private booleanbatchRemove(Collection<?> c, boolean complement) {
final Object[] elementData =this.elementData;
int r = 0, w = 0;
boolean modified = false;
try {
for (; r < size; r++)
if (c.contains(elementData[r])== complement)
elementData[w++] =elementData[r];
} finally {
// Preserve behavioralcompatibility with AbstractCollection,
// even if c.contains() throws.
if (r != size) {
System.arraycopy(elementData,r,
elementData,w,
size - r);
w += size - r;
}
if (w != size) {
// clear to let GC do its work
for (int i = w; i < size;i++)
elementData[i] = null;
modCount += size - w;
size = w;
modified = true;
}
}
return modified;
}
七、 改
八、 查
peek():返回隊列queue中index=0的元素,queue[0];如果爲空,則返回null。
contains(Object o):
public booleancontains(Object o) {
return indexOf(o) != -1;
}
九、 遍歷
ArrayList實現了內部類Itr:
private class Itrimplements Iterator<E>
ArrayList還實現了內部類ListItr,其繼承自Itr,並實現了接口ListIterator:
private class ListItrextends Itr implements ListIterator<E>
而接口ListIterator繼承自Iterator接口:interface ListIterator<E>extends Iterator<E>
所以,可以通過兩種迭代器遍歷ArrayList,分別對應到Itr和ListItr:
Iterator<String>iter = names.iterator();
ListIterator<String>iter = names.listIterator()/names.listIterator(1);
Itr就是通用的迭代器,提供hasNext和next接口:
public Iterator<E> iterator() {
return new Itr();
}
ListIterator針對ArrayList,除了提供hasNext和next接口,還提供遍歷的起始點index,並且還可以逆序遍歷:
public ListIterator<E> listIterator()/listIterator(index) {
return new ListItr(0)/ListItr(index);
}
ListIterator<String> iter = names.listIterator(3);
while (iter.hasPrevious()) {
System.out.println(iter.previous());
}
十、 子鏈表subList
ArrayList實現了List<E>subList(int fromIndex, int toIndex)
List<E>subList(int fromIndex, int toIndex)接口即返回一個新生成的子鏈表subList對象。