Iterator 和 Iterable 差别和联系
用Iterator模式实现遍历集合
Iterator模式是用于遍历集合类的标准訪问方法。它能够把訪问逻辑从不同类型的集合类中抽象出来,从而避免向client暴露集合的内部结构。
比如,假设没有使用Iterator,遍历一个数组的方法是使用索引: for(int i=0; i<array.size(); i++) { ... get(i) ... }
而訪问一个链表(LinkedList)又必须使用while循环: while((e=e.next())!=null) { ... e.data() ... }
以上两种方法client都必须事先知道集合的内部结构,訪问代码和集合本身是紧耦合。无法将訪问逻辑从集合类和client代码中分离出来,每一种集合相应一种遍历方法,client代码无法复用。
更恐怖的是,假设以后须要把ArrayList更换为LinkedList,则原来的client代码必须所有重写。
解决以上问题。Iterator模式总是用同一种逻辑来遍历集合: for(Iterator it = c.iterater(); it.hasNext(); ) { ... }
奥秘在于client自身不维护遍历集合的"指针"。全部的内部状态(如当前元素位置,是否有下一个元素)都由Iterator来维护,而这个Iterator由集合类通过工厂方法生成。因此,它知道怎样遍历整个集合。
client从不直接和集合类打交道,它总是控制Iterator,向它发送"向前","向后"。"取当前元素"的命令,就能够间接遍历整个集合。
首先看看java.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接口。因此,client不关心究竟是哪种 Iterator,它仅仅须要获得这个Iterator接口就可以。这就是面向对象的威力。
全部集合类都实现了 Collection 接口,而 Collection 继承了 Iterable 接口。
/**
* Implementing this interface allows an object to be the target of
* the "foreach" statement.
*
* @param <T> the type of elements returned by the iterator
*
* @since 1.5
*/
public interface Iterable<T> { /**
* Returns an iterator over a set of elements of type T.
*
* @return an Iterator.
*/
Iterator<T> iterator();
}
而在详细的实现类中(比方 ArrayList),则在内部维护了一个 Itr 内部类。该类继承了 Iterator 接口,它的hasNext() 和 next() 方法是和 ArrayList 实现相耦合的。
当调用 ArrayList 对象的 iterator() 方法的时候,返回该类 Itr 的一个实例,从而实现遍历 ArrayList 的功能。
public Iterator<E> iterator() {
return new Itr();
}
/**
* An optimized version of AbstractList.Itr
*/
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
为什么一定要去实现Iterable这个接口呢?为什么不直接实现Iterator接口呢?
看一下JDK中的集合类,比方List一族或者Set一族,都是实现了Iterable接口。但并不直接实现Iterator接口。 细致想一下这么做是有道理的。
由于Iterator接口的核心方法next()或者hasNext() 是依赖于迭代器的当前迭代位置的。
假设Collection直接实现Iterator接口。势必导致集合对象中包括当前迭代位置的数据(指针)。 当集合在不同方法间被传递时,由于当前迭代位置不可预置,那么next()方法的结果会变成不可预知。
除非再为Iterator接口加入一个reset()方法,用来重置当前迭代位置。 但即时这样,Collection也仅仅能同一时候存在一个当前迭代位置。
而Iterable则不然,每次调用都会返回一个从头開始计数的迭代器。 多个迭代器是互不干扰的。
Iterator 和 Iterable 差别和联系的更多相关文章
- Iterator和Iterable的区别以及使用
Iterator和Iterable的区别以及使用 1.什么是迭代器 迭代器(iterator)是一种对象,它能够用来遍历标准模板库容器中的部分或全部元素,每个迭代器对象代表容器中的确定的地址.迭代 ...
- 【转】Java迭代:Iterator和Iterable接口
Java迭代 : Iterator和Iterable接口 从英文意思去理解 Iterable :故名思议,实现了这个接口的集合对象支持迭代,是可迭代的.able结尾的表示 能...样,可以做.... ...
- Iterator 和 Iterable 区别和联系
首先预览下Java源码中的Iterator和Iterable: Iterable接口: public interface Iterable<T> {//这里只摘录接口中的抽象方法 /** ...
- iterator与iterable的区别和联系
iterator与iterable 用Iterator模式实现遍历集合Iterator模式是用于遍历集合类的标准访问方法.它可以把访问逻辑从不同类型的集合类中抽象出来,从而避免向客户端暴露集合的内 ...
- python generator iterator和iterable object
1 iterable object list.dict.set.tuple.file(在每行上iterate)等都是iterable object,但是它们不是iterator.但是它们可以转换成it ...
- iterator和iterable的区别
相关博客: http://blog.csdn.net/lipengcn/article/details/51700153 Java中Iterable和Iterator的辨析 http ...
- Java迭代 : Iterator和Iterable接口
从英文意思去理解 Iterable :故名思议,实现了这个接口的集合对象支持迭代,是可迭代的.able结尾的表示 能...样,可以做.... Iterator: 在英语中or 结尾是都是表示 .. ...
- Iterator、Iterable接口的使用及详解
Java集合类库将集合的接口与实现分离.同样的接口,可以有不同的实现. Java集合类的基本接口是Collection接口.而Collection接口必须实现Iterator接口. 以下图表示集合框架 ...
- 【转】Python 中 Iterator和Iterable的区别
Python中 list,truple,str,dict这些都可以被迭代,但他们并不是迭代器.为什么? 因为和迭代器相比有一个很大的不同,list/truple/map/dict这些数据的大小是确定的 ...
随机推荐
- 怎样获取浏览器上次的会话数据(session)
怎样获取浏览器上次的会话数据: 要知道上次会话session_id是多少? 让cookie保存的PHPSESSID的值不要浏览器一退出就被删除了? 所以我们要设置自己的session_id,不要系统自 ...
- 一张图说清Asp.NET MVC中的 RenderPage、RenderBody、RenderSection
- CentOS的ssh sftp配置及权限设置(流程相当完整)(关闭了SElinux才能上传了)
从技术角度来分析,几个要求: 1.从安全方面看,sftp会更安全一点 2.线上服务器提供在线服务,对用户需要控制,只能让用户在自己的home目录下活动 3.用户只能使用sftp,不能ssh到机器进行操 ...
- 手把手教你安装QT集成开发环境(操作系统为ubuntu10.04)
在安装QT集成开发工具包之前需要先安装build-essential和libncurses5-dev这两个开发工具和库,libncurses5-dev库是一个在Linux/Unix下广泛应用的图形函数 ...
- 函数指针&绑定: boost::functoin/std::function/bind
see link: https://isocpp.org/wiki/faq/pointers-to-members function vs template: http://stackoverflow ...
- Swift - 初始化方法返回nil表示初始化失败
自Swift1.1开始,初始化init方法便有返回nil的能力.我们可以在init声明的时候在其后面加上一个 ? 或者 ! 来表示初始化失败时可能返回nil. 比如,给Int类添加一个将字符串初始化成 ...
- javascript 中 事件流和事件冒泡
一.事件流 是描述页面接受事件的顺序,IE 使用的是时间冒泡流;而Netscape的事件采用的是事件捕获流.1.事件冒泡JS 和 HTML是通过事件的方式实现交互.事件冒泡 开始元素,将事件逐级传递, ...
- perl post 请求带参数
my $url='https://wenjinbao.winfae.com/business/dispatch_post.do?action=submitAdminLogin'; my $res ...
- 基于visual Studio2013解决面试题之0710求方优化
题目
- LintCode 二叉树的层次遍历 II
中等 二叉树的层次遍历 II 查看执行结果 42% 通过 给出一棵二叉树,返回其节点值从底向上的层次序遍历(按从叶节点所在层到根节点所在的层遍历,然后逐层从左往右遍历) 您在真实的面试中是否遇到过这个 ...