我的原則:先會用再說,內部慢慢來。
學以致用,根據場景學源碼
一、架構
1.1 常見子類 UML
1.2 簡述
- AbstractCollection 抽象類實現 Collection 接口,實現部分通用方法
- List 接口實現 Collection 接口,增加了鏈表需要的若干方法。
- AbstractList 繼承了 AbstractCollection 抽象類 ,實現了 List 接口,實現了List接口的若干個方法,目的是既拿到AbstractCollection的內部實現,又可以實現 List 接口內部的若干方法。
- List 的子類若實現了RandomAccess 接口,那麼內部就是數組 array 結構,若繼承了 AbstractSequentialList 抽象類,那麼內部就是鏈表List結構
二、AbstractList 抽象類
- AbstractList 抽象類內部並未定義新的抽象方法等待子類去實現,定義成Abstract類的目的是不用重寫父類的全部方法。
2.1 AbstractList 抽象類實現 List 接口的幾個方法
實現 List 接口的幾個方法 | 備註 |
---|---|
indexOf(Object o) | |
lastIndexOf(Object o) | |
clear() | |
addAll(int index, Collection<? extends E> c) | |
iterator() | return new Itr(); |
listIterator() | return listIterator(0); |
listIterator(final int index) | return new ListItr(index); |
subList(int fromIndex, int toIndex) | return (this instanceof RandomAccess ? new RandomAccessSubList<>(this, fromIndex, toIndex) : new SubList<>(this, fromIndex, toIndex)); |
equals(Object o) | |
hashCode() |
2.2 私有內部類 Itr
2.2.1 UML圖
2.2.2 代碼
private class Itr implements Iterator<E> {
// 遊標
int cursor = 0;
/**
* Index of element returned by most recent call to next or
* previous. Reset to -1 if this element is deleted by a call
* to remove.
*/
int lastRet = -1;
// 設置一個flag,如果外面對該 Collection 有任何寫操作,都會導致 modCount 的變化。
int expectedModCount = modCount;
// 是否還有後繼Node
public boolean hasNext() {
return cursor != size();
}
// 得到後繼節點
public E next() {
// 判斷該 Collection 是否有任何寫操作
checkForComodification();
try {
int i = cursor;
E next = get(i);
// 遊標的前一座標
lastRet = i;
// 遊標往後移動
cursor = i + 1;
return next;
} catch (IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
// Collection 允許 iterator 邊進行遍歷邊刪除
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
// 刪除
AbstractList.this.remove(lastRet);
// 正常來說 lastRet = cursor - 1
if (lastRet < cursor)
cursor--;
// 重置
lastRet = -1;
// 內部remove 保持正常狀態
expectedModCount = modCount;
} catch (IndexOutOfBoundsException e) {
throw new ConcurrentModificationException();
}
}
// 判斷該 Collection 是否有任何寫操作,如果有,拋出 ConcurrentModificationException
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
2.2.3 checkForComodification方法
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
- 該方法用於檢測 Iterator 遍歷過程中,外部是否對該Collection進行了改動,若有那麼拋出 ConcurrentModificationException 異常。
2.3 私有內部類 ListItr
- java.util.AbstractList.ListItr 繼承另一個私有內部類 Itr .從而實現了雙向遍歷。
2.3.1 ListItr私有內部類 UML圖
2.3.2 代碼
private class ListItr extends Itr implements ListIterator<E> {
// 設置遊標初始位置
ListItr(int index) {
cursor = index;
}
public boolean hasPrevious() {
return cursor != 0;
}
// 往前走,找到前一個元素,注意父類有個對應的 next 方法
public E previous() {
checkForComodification();
try {
int i = cursor - 1;
E previous = get(i);
lastRet = cursor = i;
return previous;
} catch (IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
// 往後走的遊標
public int nextIndex() {
return cursor;
}
// 往前走的遊標
public int previousIndex() {
return cursor-1;
}
// lastRet ,重新設置當前位置的元素
public void set(E e) {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
AbstractList.this.set(lastRet, e);
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
public void add(E e) {
checkForComodification();
try {
int i = cursor;
// 調取 AbstractList 實現類的 add 方法。(實例方法)
AbstractList.this.add(i, e);
// lastRet 處理的位置重新來
lastRet = -1;
cursor = i + 1;
// 調用 Iterator 的add 方法, 本身並不會造成 ConcurrentModificationException
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
}
- 看下 AbstractList.this.set(lastRet, e) ;
- 看下 AbstractList.this.add(i, e); 方法,
ListItr 內部類調用了 AbstractList 子類實例的 set方法與 add 方法。
2.4 包內 default 類 SubList
- 該類可用於部分處理 Collection 內元素,由於 List 鏈表結構是有序的,所以可以根據下標進行截取。
- 實際上,該類還是主要直接操縱了宿主List,複寫了AbstractList抽象類的一些方法,加入了檢查與offse處理。
2.4.1 UML 圖
2.4.1 代碼
class SubList<E> extends AbstractList<E> {
private final AbstractList<E> l;
private final int offset;
private int size;
// 注意一下,這裏其實沒有截取出一個新的 list ,而是同樣操作老的list,其實是個子集
SubList(AbstractList<E> list, int fromIndex, int toIndex) {
if (fromIndex < 0)
throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
if (toIndex > list.size())
throw new IndexOutOfBoundsException("toIndex = " + toIndex);
if (fromIndex > toIndex)
throw new IllegalArgumentException("fromIndex(" + fromIndex +
") > toIndex(" + toIndex + ")");
l = list;
// 跳過 N 個下標
offset = fromIndex;
// 長度相應變小
size = toIndex - fromIndex;
this.modCount = l.modCount;
}
// 先檢查,後續墊塊石頭設置 Element
public E set(int index, E element) {
rangeCheck(index);
checkForComodification();
return l.set(index+offset, element);
}
// 先檢查,後續墊塊石頭獲取 Element
public E get(int index) {
rangeCheck(index);
checkForComodification();
return l.get(index+offset);
}
public int size() {
checkForComodification();
return size; // 該 size 已經是被削減過的
}
public void add(int index, E element) {
rangeCheckForAdd(index);
checkForComodification();
l.add(index+offset, element);
this.modCount = l.modCount;
size++;
}
public E remove(int index) {
rangeCheck(index);
checkForComodification();
E result = l.remove(index+offset); // 調用父list的 remove
this.modCount = l.modCount;
size--; //實例變量 size--
return result;
}
// 刪除一定範圍內的數據,同理調用父list的 remove
protected void removeRange(int fromIndex, int toIndex) {
checkForComodification();
l.removeRange(fromIndex+offset, toIndex+offset);
this.modCount = l.modCount;
size -= (toIndex-fromIndex);
}
// 塞入一個 Collection
public boolean addAll(Collection<? extends E> c) {
// 傳入 size ,也就意味着新插入到最後
return addAll(size, c);
}
public boolean addAll(int index, Collection<? extends E> c) {
rangeCheckForAdd(index);
int cSize = c.size();
if (cSize==0)
return false;
checkForComodification();
l.addAll(offset+index, c);
this.modCount = l.modCount;
size += cSize;
return true;
}
public Iterator<E> iterator() {
return listIterator();
}
// 重寫父類的 listIterator 方法,做進一步處理
public ListIterator<E> listIterator(final int index) {
checkForComodification();
rangeCheckForAdd(index);
return new ListIterator<E>() {
private final ListIterator<E> i = l.listIterator(index+offset);
public boolean hasNext() {
return nextIndex() < size;
}
public E next() {
if (hasNext())
return i.next();
else
throw new NoSuchElementException();
}
public boolean hasPrevious() {
return previousIndex() >= 0;
}
public E previous() {
if (hasPrevious())
return i.previous();
else
throw new NoSuchElementException();
}
public int nextIndex() {
return i.nextIndex() - offset;
}
public int previousIndex() {
return i.previousIndex() - offset;
}
public void remove() {
i.remove();
SubList.this.modCount = l.modCount;
size--;
}
public void set(E e) {
i.set(e);
}
public void add(E e) {
i.add(e);
SubList.this.modCount = l.modCount;
size++;
}
};
}
public List<E> subList(int fromIndex, int toIndex) {
return new SubList<>(this, fromIndex, toIndex);
}
// 判斷下標是否超出限制
private void rangeCheck(int index) {
if (index < 0 || index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
// 判斷下標是否超出限制 forAdd
private void rangeCheckForAdd(int index) {
// 允許 index == size的情況,也就是插入一個新的,然後add操作會自動把size+1的
if (index < 0 || index > size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
// 輸出打印信息
private String outOfBoundsMsg(int index) {
return "Index: "+index+", Size: "+size;
}
// 判斷是否有外部干擾
private void checkForComodification() {
if (this.modCount != l.modCount)
throw new ConcurrentModificationException();
}
}
2.5 包內 default 類 RandomAccessSubList
- RandomAccess 意思是隨意訪問
- 該類除了實現接口 RandomAccess,對於 SubList 來說,並沒有多大的改動。
class RandomAccessSubList<E> extends SubList<E> implements RandomAccess {
RandomAccessSubList(AbstractList<E> list, int fromIndex, int toIndex) {
super(list, fromIndex, toIndex);
}
public List<E> subList(int fromIndex, int toIndex) {
return new RandomAccessSubList<>(this, fromIndex, toIndex);
}
}
三、 RandomAccess 接口(爲何要空殼?)
3.1 RandomAccess 講解
- ArrayList 實現了,LinkedList 沒實現該接口
public interface RandomAccess {
}
- 該類是幹嘛的?
- RandomAccess 意思是隨意訪問
- 該接口,表示它能快速隨機訪問存儲的元素。意味着內部實現是數組Array的,都會實現這個接口。儘管他啥事都沒做。
- RandomAccess 這個標記接口就是標記能夠隨機訪問元素的集合, 簡單來說就是底層是數組實現的集合。
- 數組 Array 支持隨機訪問, 查詢速度快, 增刪元素慢; 鏈表List 支持順序訪問, 查詢速度慢, 增刪元素快。所以對應的 ArrayList 查詢速度快,LinkedList 查詢速度慢,
3.2 RandomAccess 的常用子類
四、 AbstractSequentialList 類
- Sequential:按次序的,相繼的
- 實現此類的內部結構都是鏈表 list 結構,而並非數組 array
4.1 方法列表
方法名 | 描述 |
---|---|
public E get(int index) | - |
public E set(int index, E element) | - |
public void add(int index, E element) | 在指定index插入 |
public E remove(int index) | - |
public boolean addAll(int index, Collection<? extends E> c) | 在指定index插入另外的Collection |
public Iterator iterator() | |
public abstract ListIterator listIterator(int index) | 在指定index開始返回迭代器 |
- 內部方法均使用迭代器才能進行下標的定位。
五、番外篇
上一章節:【Java Collection】集合類 Collection 剖析(一)
上一章節:【Java Collection】常見 List 子類剖析(三)