博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Iterator 和 Iterable 区别和联系
阅读量:6709 次
发布时间:2019-06-25

本文共 5716 字,大约阅读时间需要 19 分钟。

首先预览下Java源码中的Iterator和Iterable:

Iterable接口:

1 public interface Iterable
{
//这里只摘录接口中的抽象方法2 /**3 * Returns an iterator over elements of type {
@code T}.4 *5 * @return an Iterator.6 */7 Iterator
iterator();8 9 }

Iterator接口:

public interface Iterator
{ /** * Returns {
@code true} if the iteration has more elements. * (In other words, returns {
@code true} if {
@link #next} would * return an element rather than throwing an exception.) * * @return {
@code true} if the iteration has more elements */ boolean hasNext(); /** * Returns the next element in the iteration. * * @return the next element in the iteration * @throws NoSuchElementException if the iteration has no more elements */ E next();}

 

用Iterator模式实现遍历集合 

        Iterator模式是用于遍历集合类的标准访问方法。它可以把访问逻辑从不同类型的集合类中抽象出来,从而避免向客户端暴露集合的内部结构。

        例如,如果没有使用Iterator,遍历一个数组的方法是使用索引: for(int i=0; i<array.size(); i++) { ... get(i) ... }

        而访问一个链表(LinkedList)又必须使用while循环: while((e=e.next())!=null) { ... e.data() ... } 

        以上两种方法客户端都必须事先知道集合的内部结构,访问代码和集合本身是紧耦合,无法将访问逻辑从集合类和客户端代码中分离出来,每一种集合对应一种遍历方法,客户端代码无法复用。

        更恐怖的是,如果以后需要把ArrayList更换为LinkedList,则原来的客户端代码必须全部重写。

        解决以上问题,Iterator模式总是用同一种逻辑来遍历集合: for(Iterator it = c.iterater(); it.hasNext(); ) { ... } 

        奥秘在于客户端自身不维护遍历集合的"指针",所有的内部状态(如当前元素位置,是否有下一个元素)都由Iterator来维护,而这个Iterator由集合类通过工厂方法生成,因此,它知道如何遍历整个集合。 

        客户端从不直接和集合类打交道,它总是控制Iterator,向它发送"向前","向后","取当前元素"的命令,就可以间接遍历整个集合。 

        首先看看.util.Iterator接口的定义: 

                public interface Iterator { boolean hasNext(); Object next(); void remove(); } 

        依赖前两个方法就能完成遍历,典型的代码如下: 

                for(Iterator it = c.iterator(); it.hasNext(); ) { Object o = it.next(); // 对o的操作... } 

        每一种集合类返回的Iterator具体类型可能不同,Array可能返回ArrayIterator,Set可能返回 SetIterator,Tree可能返回TreeIterator,但是它们都实现了Iterator接口,因此,客户端不关心到底是哪种 Iterator,它只需要获得这个Iterator接口即可,这就是面向对象的威力。 

        所有集合类都实现了 Collection 接口,而 Collection 继承了 Iterable 接口。

 1 public interface Collection<E> extends Iterable<E> {  } 

 而在具体的实现类中(比如 ArrayList),则在内部维护了一个 Itr 内部类,该类继承了 Iterator 接口,它的hasNext() 和 next() 方法是和 ArrayList 实现相耦合的。当调用 ArrayList 对象的 iterator() 方法的时候,返回该类 Itr 的一个实例,从而实现遍历 ArrayList 的功能。

 

1  /** 2      * An optimized version of AbstractList.Itr 3      */ 4     private class Itr implements Iterator
{ 5 int cursor; // index of next element to return 6 int lastRet = -1; // index of last element returned; -1 if no such 7 int expectedModCount = modCount; 8 9 public boolean hasNext() {10 return cursor != size;11 }12 13 @SuppressWarnings("unchecked")14 public E next() {15 checkForComodification();16 int i = cursor;17 if (i >= size)18 throw new NoSuchElementException();19 Object[] elementData = ArrayList.this.elementData;20 if (i >= elementData.length)21 throw new ConcurrentModificationException();22 cursor = i + 1;23 return (E) elementData[lastRet = i];24 }25 26 public void remove() {27 if (lastRet < 0)28 throw new IllegalStateException();29 checkForComodification();30 31 try {32 ArrayList.this.remove(lastRet);33 cursor = lastRet;34 lastRet = -1;35 expectedModCount = modCount;36 } catch (IndexOutOfBoundsException ex) {37 throw new ConcurrentModificationException();38 }39 }

在遍历元素或者删除元素时,必须要进行next()方法,要不然,迭代器不能正常运行:如

1 /**  2  *太极云软件技术股份有限公司版权所有 1990-2016. http://www.tyky.com.cn 3  * @file com.hoojjack.spring_study.tutorialspoint 4  *  5  */ 6 package com.hoojjack.spring_study.tutorialspoint; 7  8 import java.util.ArrayList; 9 import java.util.Iterator;10 import java.util.List;11 12 /** 13  * @ClassName: TestIterator 14  * @Description: TODO(这里用一句话描述这个类的作用) 15  * @author hoojjack 16  * @date 2017年5月15日 下午6:42:15 17  *  18  */19 public class TestIterator {20     public static void main(String args[]){21         List
list = new ArrayList
();22 list.add("h");23 list.add("o");24 list.add("o");25 list.add("j");26 Iterator
it = list.iterator();27 while(it.hasNext()){28 //it.next();//注释这行会报错,具体原因请看源码29 it.remove();30 break;31 }32 for(String i:list){33 System.out.println(i);34 }35 }36 37 38 }
1  public E remove(int index) { 2         rangeCheck(index); 3  4         modCount++; 5         E oldValue = elementData(index); 6  7         int numMoved = size - index - 1; 8         if (numMoved > 0) 9             System.arraycopy(elementData, index+1, elementData, index,10                              numMoved);11         elementData[--size] = null; // clear to let GC do its work12 13         return oldValue;14     }

 

 

为什么一定要去实现Iterable这个接口呢?为什么不直接实现Iterator接口呢?

 

        看一下JDK中的集合类,比如List一族或者Set一族,都是实现了Iterable接口,但并不直接实现Iterator接口。 仔细想一下这么做是有道理的。

        因为Iterator接口的核心方法next()或者hasNext() 是依赖于迭代器的当前迭代位置的。 如果Collection直接实现Iterator接口,势必导致集合对象中包含当前迭代位置的数据(指针)。 当集合在不同方法间被传递时,由于当前迭代位置不可预置,那么next()方法的结果会变成不可预知。 除非再为Iterator接口添加一个reset()方法,用来重置当前迭代位置。 但即时这样,Collection也只能同时存在一个当前迭代位置。 而Iterable则不然,每次调用都会返回一个从头开始计数的迭代器。 多个迭代器是互不干扰的。

直接继承Iterator,从Iterator接口可以看出需要子类实现next(),hasNext()方法,假设都交给List去实现,那么获取list的Iterator()时就会出现上面解释那样,而继承Iterable接口,则需要每次List返回一个新的Iterator对象(见ArrayList的new Itr()),因此可以避免上述说到的原因。

 

【reference】

1、http://blog.csdn.net/zq602316498/article/details/39337899

转载于:https://www.cnblogs.com/hoojjack/p/6857911.html

你可能感兴趣的文章
局域网
查看>>
javascript之encodeURI
查看>>
Python中type和object
查看>>
总结一下有关css选择器方面的知识:
查看>>
(HW)rod cutting(Java)
查看>>
jq挑战30天——模拟电子鼓+小程序
查看>>
IKE协议
查看>>
浏览器同部署了https的服务器交互的过程
查看>>
redis写shell与ssh免密码登陆
查看>>
2013337朱荟潼 Linux第三章读书笔记——进程管理
查看>>
《大话设计模式》读书笔记-第9章 原型模式
查看>>
排序五:快速排序
查看>>
POJ - 3264——Balanced Lineup(入门线段树)
查看>>
Python中的多进程与多线程/分布式该如何使用
查看>>
C语言基础教程源码
查看>>
【Android游戏开发十五】关于Android 游戏开发中 OnTouchEvent() 触屏事件的性能优化笔记!...
查看>>
微信公众号
查看>>
LeetCode - 1. Two Sum
查看>>
[LeetCode]: 64: Minimum Path Sum
查看>>
vuex简介(转载)
查看>>