Java容器類原始碼分析之Iterator與ListIterator迭代器(基於JDK8)

Java菜分享發表於2019-04-10

一、基本概念

迭代器是一個物件,也是一種設計模式,Java有兩個用來實實現迭代器的介面,分別是Iterator介面和繼承自Iterator的ListIterator介面。實現迭代器介面的類的物件有遍歷集合物件,選擇集合中的元素和刪除集合中元素的方法。而在使用它時不必知道該集合物件底層的結構。Java類庫中實現Iterator介面的迭代器只能正向遍歷集合中的元素,而實現ListIterator介面的迭代器不僅能夠正向遍歷,還能夠反向遍歷集合中的元素。

二、原始碼分析

2.1、Iterator介面與ListIterator介面的繼承與實現

Java容器類原始碼分析之Iterator與ListIterator迭代器(基於JDK8)


圖2.1 Java迭代器類的繼承與介面實現(部分)

ListIterator介面繼承了Iterator介面。在AbstractList、ArrayList和Vector這三個類中的內部類ListItr實現了ListIterator介面,這三個類的內部類ListItr又分別繼承了在這三個類中實現了Iterator介面的內部類Itr。實現ListIterator的類還有LinkedList的內部類ListItr。實現Iterator的類還有LinkedList的內部類DescendingIterator,HashMap的內部類EntryIterator,KeyIterator,ValueIterator,以及TreeMap的內部類PrivateEntryIterator等。

2.2、迭代器介面方法

1)迭代器的向前移動與向後移動圖解

Java容器類原始碼分析之Iterator與ListIterator迭代器(基於JDK8)


2)Iterator介面方法


package java.util;
import java.util.function.Consumer;
public interface Iterator<E> {
    boolean hasNext();
/*   在Java中,這個方法的具體實現一般用來在遍歷容器時,呼叫該方法使迭代器向前移動一位,來檢測集合中是否還有下一個元素,還有下一個元素返回true,否則返回false*/
 
    E next();
/*   實現這個方法,在遍歷容器時,呼叫該方法將迭代器向前移動一位,並將迭代器越過的一個元素作為方法的返回值。該方法用來返回集合中下一個元素。
 在呼叫next()方法前,先呼叫hasNext()方法判斷集合中是否還有下一個元素 */ 
    default void remove() { throw new UnsupportedOperationException("remove"); } 
/*   實現這個方法,用來刪除在迭代器呼叫next()方法迭代器越過的一個元素*/ 
    default void forEachRemaining(Consumer<? super E> action) { Objects.requireNonNull(action); while (hasNext()) action.accept(next()); }
/*   實現這個方法來順序遍歷容器中的每個元素,用來實現集合類的ForEach遍歷操作*/ 
}
複製程式碼



3)ListIterator介面方法


package java.util;
public interface ListIterator<E> extends Iterator<E> {
  
    boolean hasNext();//同Iterator介面,用來檢測迭代器前面是否還有元素
   
    E next();
//  同Iterator介面,使迭代器向前移動一位,獲得迭代器越過的下一個元素
    boolean hasPrevious();
//  實現這個方法來檢測當前迭代器位置後面是否有元素,用於反向遍歷
 
    E previous();
/*   實現這個方法,將迭代器向後移動一位,並將迭代器越過的後面的一個元素作為方法返回值,在呼叫該方法前需要呼叫hasPrevious方法來判斷迭代器前是否有元素 */
   
    int nextIndex();//實現該方法獲取迭代器前面一個元素的索引
    int previousIndex();//實現該方法獲取迭代器後面一個元素的索引
    void remove();
/*   實現該方法,用來刪除迭代器呼叫next()方法或呼叫previous()方法時迭代器越過的一個元素 */
    void set(E e);//實現該方法在迭代器遍歷時修改元素
    void add(E e);//實現該方法在迭代器遍歷時新增元素
}
複製程式碼



2.3、容器類與迭代器的關係

1)Iterator介面。閱讀原始碼可知,Collectiion介面實現了Iterable介面,Iterable有一個返回一個Iterator<T>物件的iterator()方法,所以繼承和實現了Collection介面的所有容器類及其子類和實現類都有一個返回Iterator物件的的iterator()方法。Java中有很多容器類中都設計有實現了Iterator介面的內部類,如ArrayList和LinkedList等類。HashMap和TreeMap類中也包含有實現了Iterator的內部類,來對Map中的KeySet、Value和EntrySet進行迭代。Iterable介面的原始碼如下:


public interface Iterable<T> {
    Iterator<T> iterator();//實現這個方法,該方法返回一個Iterator迭代器物件。
    default void forEach(Consumer<? super T> action) {
        Objects.requireNonNull(action);
        for (T t : this) {
            action.accept(t);
        }
    }//實現這個方法來對容器進行ForEach遍歷
  
    default Spliterator<T> spliterator() {
        return Spliterators.spliteratorUnknownSize(iterator(), 0);
    }
}
複製程式碼



2)ListIterator介面。檢視原始碼可以發現,List介面中有兩個返回ListIterator<T>物件的方法,如下。List介面下的的ArrayList和LinkedList都有返回ListIterator物件的方法。

ListIterator<E> listIterator();//實現這個方法,該方法返回一個ListIterator迭代器物件,迭代器初始化後,一般迭代器位於在容器第一個元素後面。
ListIterator<E> listIterator(int index);//實現這個方法,返回一個指定了開始遍歷容器時迭代器初始位置的ListIterator迭代器物件
複製程式碼

  • ArrayList類設計有實現了ListIterator介面的內部類ListItr(不過ArrayList的listIterator(final int index)方法並未使用這個內部類,而是在方法中又設計了一個ListIterator匿名內部類作為方法返回值,可以發現ArrayList的Iterator()方法也是呼叫了這個方法來構建迭代器物件)。ArrayList類中部分有關原始碼如下
  private class ListItr extends Itr implements ListIterator<E> {
        ListItr(int index) {
            super();
            cursor = index;
        }
複製程式碼


  public Iterator<E> iterator() {
            return listIterator();
        }
        public ListIterator<E> listIterator(final int index) {
            checkForComodification();
            rangeCheckForAdd(index);
            final int offset = this.offset;
            return new ListIterator<E>() {//返回了一個ListIterator匿名內部類
                int cursor = index;
                int lastRet = -1;
                int expectedModCount = ArrayList.this.modCount;
                public boolean hasNext() {
                    return cursor != SubList.this.size;
                }
複製程式碼



  • LinkedList類也有一個內部類ListItr實現了ListIterator介面,LinkedList的listIterator()方法返回了這個內部類的例項。LinkedList中部分有關原始碼如下



    public ListIterator<E> listIterator(int index) {
        checkPositionIndex(index);
        return new ListItr(index);
    }
    private class ListItr implements ListIterator<E> {
複製程式碼


歡迎工作一到五年的Java工程師朋友們加入Java程式設計師開發: 721575865

群內提供免費的Java架構學習資料(裡面有高可用、高併發、高效能及分散式、Jvm效能調優、Spring原始碼,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多個知識點的架構資料)合理利用自己每一分每一秒的時間來學習提升自己,不要再用"沒有時間“來掩飾自己思想上的懶惰!趁年輕,使勁拼,給未來的自己一個交代!


相關文章