关于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设计模式。索引

    书到用时方恨少,事非通过不知难。点滴积累,你就会成为技术上的巨人!接口

相关文章
相关标签/搜索