1. 程式人生 > >JAVA集合原始碼攻堅戰(6)——AbstractList

JAVA集合原始碼攻堅戰(6)——AbstractList

前言

前面我們已經分析過AbstractCollection和List這兩個介面類了,接下來分析AbstractList。

AbstractList的父母

剛剛靈光一閃,想到一個不太恰當的比喻。比如AbstractList,繼承了AbstractCollection,實現了List介面,那麼AbstractCollection相當於是父親,子承父業,List相當於母親,百善孝為先,應該實現母親的願望(方法)。

子承父業

首先在AbstractCollection中,我們提過,AbstractCollection要求它的實現類一定要Iterator()和size()方法。而在AbstractList中,已經實現了它的Iterator()方法

public Iterator<E> iterator() {
        return new Itr(); // Itr類是自己實現的
    }

然後AbstractList還自己定義了一個抽象方法

abstract public E get(int index);

從這裡其實就可以看出,get這個方法能根據索引index來返回元素,奠定了List這一系列裡,他的實現類都是有序的,能根據索引來查詢元素。 另外,要實現一個不可修改的列表,程式設計師只需要擴充套件這個類並提供get(int)和size()方法的實現。 要實現可修改的列表,程式設計師必須另外覆蓋set(int, E)方法(否則會丟擲一個UnsupportedOperationException)。 如果列表是可變大小,則程式設計師必須另外覆蓋add(int, E)和remove(int)方法。

實現的方法

1、public int indexOf(Object o) 從頭開始查詢指定元素首次出現的位置

    public int indexOf(Object o) {
    	// 獲取一個list迭代器,因為使用預設構造器,當前遊標位置為起始位置0,也即從前往後遍歷
        ListIterator<E> it = listIterator();
        if (o==null) {
            while (it.hasNext())
                if (it.next()==null)
                    return it.previousIndex();
        } else {
            while (it.hasNext())
            	// 利用equals方法來進行比較
                if (o.equals(it.next()))
                    return it.previousIndex();
        }
        return -1;
    }

注意,這裡的迭代器listIterator是AbstractList自己實現的,我們後面再詳細分析。同時,要注意遊標並不是直接指向元素的,而是位於元素之間,實際當迴圈中的if語句匹配成功時,遊標已經在我們要找的那個元素後面了,所以需要返回的是前一個遊標的位置。 2、public int lastIndexOf(Object o) 從後往前遍歷查詢指定元素首次出現的位置

public int lastIndexOf(Object o) {
    	// 獲取一個遊標位置從末尾開始的迭代器,使用有引數的構造器
        ListIterator<E> it = listIterator(size());
        if (o==null) {
            while (it.hasPrevious())
                if (it.previous()==null)
                    return it.nextIndex();
        } else {
            while (it.hasPrevious())
                if (o.equals(it.previous()))
                    return it.nextIndex();
        }
        return -1;
    }

3、 public void clear() 清除元素 protected void removeRange(int fromIndex, int toIndex) 範圍刪除元素

public void clear() {
        removeRange(0, size());
    }

protected void removeRange(int fromIndex, int toIndex) { // 刪除包含fromIndex,不包含toIndex的範圍內的元素
		// 獲取一個遊標位於fromIndex元素之前的迭代器
        ListIterator<E> it = listIterator(fromIndex);
        for (int i=0, n=toIndex-fromIndex; i<n; i++) { // 通過i<n判斷,不會刪除toIndex該位置的元素
            it.next();
            it.remove();
        }
    }

4、public boolean addAll(int index, Collection<? extends E> c) 在指定的索引位置新增元素,新增的元素順序按照給定的集合的迭代器返回元素順序

public boolean addAll(int index, Collection<? extends E> c) {
    	// 索引越界檢查
        rangeCheckForAdd(index);
        boolean modified = false;
        for (E e : c) {
        	// 需要重寫add(E)和add(index,E)方法,否則丟擲UnsupportedOperationException異常
            add(index++, e);
            modified = true;
        }
        return modified;
    }
private void rangeCheckForAdd(int index) {
        if (index < 0 || index > size())
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

迭代器

AbstractList自己內部實現了兩個迭代器:Itr和ListItr。 ListItr本身也是繼承了Itr的。我們先來看Itr

Itr迭代器

先來看完整的實現程式碼

    private class Itr implements Iterator<E> {
        /**
         * Index of element to be returned by subsequent call to next.
         * 指向後續呼叫next()方法返回的那個元素的索引
         */
        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.
         * 指向最近一次呼叫next或previous方法返回的元素的索引。如果該元素被刪除了,則重置為-1。
         */
        int lastRet = -1;

        /**
         * The modCount value that the iterator believes that the backing
         * List should have.  If this expectation is violated, the iterator
         * has detected concurrent modification.
         * modCount這個變數是後續的list實現類應該有的。如果違反了這一點,迭代器會出現併發的修改操作。
         */
        int expectedModCount = modCount;

        // 實現了Iterator介面的hasNext方法
        public boolean hasNext() {
            return cursor != size();
        }

        // 實現了Iterator介面的next方法
        public E next() {
        	// 併發操作檢查,如果在獲取元素的時候,對元素進行修改,則丟擲異常
            checkForComodification();
            try {
                int i = cursor;
                E next = get(i);
                lastRet = i;
                cursor = i + 1;
                return next;
            } catch (IndexOutOfBoundsException e) {
                checkForComodification();
                throw new NoSuchElementException();
            }
        }

        // 實現了Iterator介面的remove方法
        // 根據Iterator對remove的描述,該方法應該只有在呼叫過一次next方法後,才能呼叫該方法。
        public void remove() {
        	// 如果lastRet<0,說明之前並沒有呼叫過next,或者已經被移除,直接丟擲異常。
            if (lastRet < 0)
                throw new IllegalStateException();
            // 檢查是否有併發操作
            checkForComodification();

            try {
            	// 呼叫AbstractList的子類實現的remove(index)方法
                AbstractList.this.remove(lastRet);
                if (lastRet < cursor)// 如果刪除的元素的索引在當前遊標前面,那麼刪除元素後,遊標要向前移動一個單位
                    cursor--;
                lastRet = -1;// 重置為-1
                expectedModCount = modCount;	// 一個修改操作結束後,重新設定檢查併發的引數的值。
                								//其實這是避免子類實現了其他方法,會修改modCount值,
                								//造成expectedModCount與modCount不一致
            } catch (IndexOutOfBoundsException e) {
                throw new ConcurrentModificationException();
            }
        }
        
        // 檢查併發修改操作
        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }

ListItr迭代器

    // 繼承Itr,實現了ListIterator,是對Itr的一個增強版
    // ListItr 實現了ListIterator,支援雙向遍歷
    private class ListItr extends Itr implements ListIterator<E> {
    	// 構造器,直接設定遊標指向的位置
        ListItr(int index) {
            cursor = index;
        }

        // 判斷前面是否還有元素
        public boolean hasPrevious() {
            return cursor != 0;
        }

        // 獲取前一個元素
        public E previous() {
        	// 檢查併發操作
            checkForComodification();
            try {
                int i = cursor - 1;		// 遊標向前移動一位
                E previous = get(i);	// 呼叫子類的get(index)方法
                lastRet = cursor = i;	// 返回剛剛查詢的那個元素的索引
                return previous;
            } catch (IndexOutOfBoundsException e) {
                checkForComodification();
                throw new NoSuchElementException();
            }
        }

        public int nextIndex() {
            return cursor;
        }

        public int previousIndex() {
            return cursor-1;
        }

        // 和remove類似,
        // 根據ListIterator對set的描述,該方法應該只有在呼叫過一次next或者previous後,才能呼叫該方法。
        public void set(E e) {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();	// 檢查併發操作

            try {
            	// 呼叫實現類的set(index,E)方法
                AbstractList.this.set(lastRet, e);
                expectedModCount = modCount;	// 操作記錄數設定
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }

        public void add(E e) {
            checkForComodification();

            try {
                int i = cursor;
                // 在當前遊標位置,呼叫子類的add方法插入元素
                AbstractList.this.add(i, e);
                lastRet = -1;	// 重置lastRet
                cursor = i + 1;	// 插入元素後,遊標位置向後移動一位
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }
    }