【Java Collection】List 剖析(二)

我的原則:先會用再說,內部慢慢來。
學以致用,根據場景學源碼


一、架構

1.1 常見子類 UML

在這裏插入圖片描述

1.2 簡述

  1. AbstractCollection 抽象類實現 Collection 接口,實現部分通用方法
  2. List 接口實現 Collection 接口,增加了鏈表需要的若干方法。
  3. AbstractList 繼承了 AbstractCollection 抽象類 ,實現了 List 接口,實現了List接口的若干個方法,目的是既拿到AbstractCollection的內部實現,又可以實現 List 接口內部的若干方法。
  4. List 的子類若實現了RandomAccess 接口,那麼內部就是數組 array 結構,若繼承了 AbstractSequentialList 抽象類,那麼內部就是鏈表List結構

=== 點擊查看top目錄 ===

二、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圖

在這裏插入圖片描述
=== 點擊查看top目錄 ===

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 異常。

=== 點擊查看top目錄 ===

2.3 私有內部類 ListItr

  • java.util.AbstractList.ListItr 繼承另一個私有內部類 Itr .從而實現了雙向遍歷。
2.3.1 ListItr私有內部類 UML圖

在這裏插入圖片描述

=== 點擊查看top目錄 ===

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 方法。

=== 點擊查看top目錄 ===

2.4 包內 default 類 SubList

  • 該類可用於部分處理 Collection 內元素,由於 List 鏈表結構是有序的,所以可以根據下標進行截取。
  • 實際上,該類還是主要直接操縱了宿主List,複寫了AbstractList抽象類的一些方法,加入了檢查與offse處理。
2.4.1 UML 圖

在這裏插入圖片描述

=== 點擊查看top目錄 ===

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

=== 點擊查看top目錄 ===

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

=== 點擊查看top目錄 ===

三、 RandomAccess 接口(爲何要空殼?)

3.1 RandomAccess 講解

  • ArrayList 實現了,LinkedList 沒實現該接口
public interface RandomAccess {
}
  • 該類是幹嘛的?
  1. RandomAccess 意思是隨意訪問
  2. 該接口,表示它能快速隨機訪問存儲的元素。意味着內部實現是數組Array的,都會實現這個接口。儘管他啥事都沒做。
  3. RandomAccess 這個標記接口就是標記能夠隨機訪問元素的集合, 簡單來說就是底層是數組實現的集合。
  4. 數組 Array 支持隨機訪問, 查詢速度快, 增刪元素慢; 鏈表List 支持順序訪問, 查詢速度慢, 增刪元素快。所以對應的 ArrayList 查詢速度快,LinkedList 查詢速度慢,

=== 點擊查看top目錄 ===

3.2 RandomAccess 的常用子類

在這裏插入圖片描述
=== 點擊查看top目錄 ===

四、 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開始返回迭代器
  • 內部方法均使用迭代器才能進行下標的定位。

=== 點擊查看top目錄 ===


五、番外篇

上一章節:【Java Collection】集合類 Collection 剖析(一)
上一章節:【Java Collection】常見 List 子類剖析(三)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章