關於Iterator探究和思考

    前兩天,一哥們拿着同一個問題連續找了我兩次。一開始覺得沒什麼說的東西,後來越研究越以爲有意思,今天閒來無事,寫出來跟你們分享。java

    問題是這樣的:「迭代集合時,Iterator it=c.iterator() 返回的到底接口Iterator的哪一個實現類?」。剛開始我隨口就是「查查API不就知道了麼」,後來證實查API還真就「不知道」。API顯示Iterator只有三個實現類(BeanContextSupport.BCSIterator, EventReaderDelegate, Scanner),可是哪個都不像是跟迭代有關的。後來查源碼,發現Iterator設計和實現的精妙之處。編程

jdk源碼 Iterator接口定義以下:設計模式

 

 public interface Iterator<E> {
     boolean hasNext();//判斷容器內是否還有可供訪問的元素
     E next();//返回迭代器剛越過的元素的引用,返回值是Object,須要強制轉換成本身須要的類型
     void remove();//刪除迭代器剛越過的元素
 }

 

咱們都知道,其實在編程過程當中常用的,也只有hasNext()和next()。通常咱們都是這麼進行迭代:數組

 

Iterator it=c.iterator();
while(it.hasNext()){
  Object o=it.next();
  //do something
}

 

不難發現,不管迭代的是List集合仍是Set集合,也不管集合底層是採用數組實現的ArrayList、Vector、HashSet,或者是採用鏈表實現的LinkedList、又或者是採用二叉樹實現的TreeSet,通通都是經過統一的方法hasNext()、next()來判斷、獲取下一個元素,可是具體的內部操做確定是不同的,那Iterator是怎麼作到的呢?其實,並非Iterator怎麼作到,而是每個集合類本身分別來進行實現的。下面我以ArrayList爲例,跟你們一塊兒分析一下jdk的精妙實現:ide

    衆所周知,ArrayList的內部實現採用數組,因此咱們只須要記錄相應位置的索引就能夠了,其方法的實現也是比較簡單的。它經過定義內部類內部類,來實現Iterator接口來實現的,以下:this

 

 private class Itr implements Iterator<E> {
  int cursor = 0;//cursor從0開始,表示下一個元素的索引位置
  int lastRet = -1;//lastRet從-1開始,表示上一個元素的索引位置
  int expectedModCount = modCount;//記錄對集合修改的次數,主要是用於實現ArrayList集合的快速失敗機制
  /**
   *hasNext()只需判斷當前位置是否是處在最後一個了便可.
   */
  public boolean hasNext() {
             return cursor != size();
  }
  /**
   * next()實現其實也是比較簡單的,只要返回cursor索引位置處的元素便可,而後修改cursor、lastRet便可.
   */
  public E next() {
             checkForComodification();//主要用來判斷集合的修改次數是否合法,即用來判斷遍歷過程當中集合是否被修改過.
      try {
    E next = get(cursor);//從底層實現數組裏取得當前元素
    lastRet = cursor++;//lastRet+1
    return next;//返回當前元素
      } catch (IndexOutOfBoundsException e) {
    checkForComodification();
    throw new NoSuchElementException();
      }
  }
  /**
   * 調用ArrayList自己的remove()方法刪除lastRet位置元素,而後修改modCount便可.
   */
  public void remove() {
      if (lastRet == -1)
       throw new IllegalStateException();
             checkForComodification();
      try {
    AbstractList.this.remove(lastRet);//從底層實現數組裏刪除上一個元素
    if (lastRet < cursor)
        cursor--;//因爲當前元素要填補到上一個元素的位置去,因此當前元素下標-1
    lastRet = -1;
    expectedModCount = modCount;//把集合的修改次數賦值給expectedModCount
      } catch (IndexOutOfBoundsException e) {
       throw new ConcurrentModificationException();
      }
  }
 
  final void checkForComodification() {
      if (modCount != expectedModCount)
   throw new ConcurrentModificationException();
  }
   }

 

這就是ArrayList的Iterator接口的實現。有人會問「那豈不是每個集合類都要提供對Iterator的實現啊?」,對!Iterator只提供方法,你要想使用其進行迭代遍歷,就必須提供對它的迭代實現。實際上,LinkedList、Vector、HashSet、TreeSet等集合的Iterator實現也都採用相似的設計思路。設計

    經過以上探究,咱們不難看出,Iterator給咱們提供了一種通用的遍歷各類集合的方法,它能夠把訪問邏輯從不一樣類型的集合類中抽象出來,作到了訪問代碼和集合自己的解耦,從而避免向客戶端暴露集合的內部結構。今後,客戶端能夠不直接和集合類打交道,它只須要控制Iterator,向它發送「向前」、「向後」、「取當前元素」、「刪元素」的命令,就能夠間接遍歷和操做整個集合,而且這些客戶端代碼仍是能夠複用的。其實,這就是java中很是著名的Iterator設計模式。索引

    書到用時方恨少,事非通過不知難。點滴積累,你就會成爲技術上的巨人!接口

相關文章
相關標籤/搜索