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,向它发送"向前","向后","取当前元素"的命令,就可以间接遍历整个集合。
首先看看java.util.Iterator接口的定义:
public interface Iterator { boolean hasNext(); Object next(); void remove(); }
依赖前两个方法就能完成遍历,典型的代码如下:
for(Iterator it = c.iterator(); it.hasNext(); ) { Object o = it.next(); // 对o的操作... }
在JDK1.5中,还对上面的代码在语法上作了简化(但是限于只读,如果需要remove,还是直接使用iterator):
// Type是具体的类型,如String。 for(Type t : c) { // 对t的操作... }
每一种集合类返回的Iterator具体类型可能不同,Array可能返回ArrayIterator,Set可能返回SetIterator,Tree可能返回TreeIterator,但是它们都实现了Iterator接口,因此,客户端不关心到底是哪种Iterator,它只需要获得这个Iterator接口即可,这就是面向对象的威力。
在遍历的过程中出现java.util.ConcurrentModificationException的问题参http://www.blogjava.net/EvanLiu/archive/2008/08/31/224453.html
如果想用foreach遍历自定义类的集合,自定义类通常需要实现implement iterable接口. 该接口定义了Iterator<T> iterator()方法. 有些时候这个iterator方法可以供用类里面的集合属性.iterator()返回.
所以我们首先要了解到iterator与iterable这2个接口的具体定义是什么:
首先附上这两个接口JDK中的定义:
package java.lang;
import java.util.Iterator;
public interface Iterable<T> {
Iterator<T> iterator();
}
package java.util;
public interface Iterator<E> {
boolean hasNext();
E next();
void remove();
}
可以看到这两个接口来自于不同的package中,实现Iterable接口可以使用foreach方法来遍历。 但Iterable中只是用一个方法来返回一个Iterator类型实例。
示例:
public class Teacher implements Iterable{
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Iterator iterator() {
return new Itr();
}
public static void main(String[] args) {
Teacher t = new Teacher();
t.setName("aaaaaaa");
t.setAge(23);
for (Object o : t) {
System.out.println(o.toString());
}
}
private class Itr implements Iterator{
private int cursor=0; // 属性的索引
private Field[] fields = Teacher.class.getDeclaredFields(); // 属性的数组
public boolean hasNext() {
return cursor!=(Teacher.class.getDeclaredFields().length);
}
public Object next() {
Object o=null;
try{
fields[cursor].setAccessible(true); // 让内部类可以访问外部类的私有属性的值
o = fields[cursor].getName()+" "+fields[cursor].get(Teacher.this);
cursor++;
}catch(Exception e){
System.out.println(e);
}
return o;
}
public void remove() {
// TODO Auto-generated method stub
}
}
}
示例2:
import java.util.Iterator;
//测试类
public class Exec {
public static void main(String[] args) throws Exception {
// 创建学生集合类
Students students = new Students(10);
// 通过for each语句迭代循环学生集合类的每个元素
for (Object obj : students) {
Student stu = (Student) obj;
System.out.println(stu.getSid() + ":" + stu.getName());
}
}
}
// 支持for each迭代循环的学生集合类
class Students implements Iterable {
// 存储所有学生类的数组
private Student[] stus;
// 该构造函数可以生成指定大小的学生类变量数组,并初始化该学生类变量数组
public Students(int size) {
stus = new Student[size];
for (int i = 0; i < size; i++) {
stus[i] = new Student(String.valueOf(i), "学生" + String.valueOf(i));
}
}
// 实现Iterable接口的重要方法,返回自定义的迭代类变量
public Iterator iterator() {
return new StudentIterator();
}
// 实现Iterator接口的私有内部类,外界无法直接访问
private class StudentIterator implements Iterator {
// 当前迭代元素的下标
private int index = 0;
// 判断是否还有下一个元素,如果迭代到最后一个元素就返回false
public boolean hasNext() {
return index != stus.length;
}
// 返回当前元素数据,并递增下标
public Object next() {
return stus[index++];
}
// 这里不支持,抛出不支持操作异常
public void remove() {
throw new UnsupportedOperationException();
}
}
}
// 学生类
class Student {
// 学生学号
private String sid;
// 学生姓名
private String name;
// 默认构造函数
public Student() {
}
// 支持属性值初始化的构造函数
public Student(String sid, String name) {
setSid(sid);
setName(name);
}
// 学生学号的读取函数
public String getSid() {
return sid;
}
// 学生学号的设置函数
public void setSid(String sid) {
this.sid = sid;
}
// 学生姓名的读取函数
public String getName() {
return name;
}
// 学生姓名的设置函数
public void setName(String name) {
this.name = name;
}
// 格式化字符信息输出
public String toString() {
return this.sid + ":" + this.name;
}
}
如上面的例子描述,JAVA中得各种集合实际上都对Iterator接口的3个方法重新覆盖了,而如果要使用foreach方法来遍历,那么就必须实现Iterable接口,一般实现方式就如上,实际上可以用匿名内部类简化上面的操作:
public Iterator iterator() {
return new Iterator ()
{
private int index = 0;
public boolean hasNext() {
return index != stus.length;
}
public Object next() {
return stus[index++];
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
看一下JDK中的集合类,比如List一族或者Set一族,
都是实现了Iterable接口,但并不直接实现Iterator接口。
仔细想一下这么做是有道理的。因为Iterator接口的核心方法next()或者hasNext()
是依赖于迭代器的当前迭代位置的。
如果Collection直接实现Iterator接口,势必导致集合对象中包含当前迭代位置的数据(指针)。
当集合在不同方法间被传递时,由于当前迭代位置不可预置,那么next()方法的结果会变成不可预知。
除非再为Iterator接口添加一个reset()方法,用来重置当前迭代位置。
但即时这样,Collection也只能同时存在一个当前迭代位置。
而Iterable则不然,每次调用都会返回一个从头开始计数的迭代器。
多个迭代器是互不干扰的。
在JAVA SE5中,大量的类都是Iterable类型,主要包括所有的Collection类(不包括各种Map)
比如JAVA源码中得Collection接口定义如下:
public interface Collection<E> extends Iterable<E> {
int size();
boolean isEmpty();
boolean contains(Object o);
Iterator<E> iterator();
Object[] toArray();
<T> T[] toArray(T[] a);
// Modification Operations
boolean add(E e);
boolean remove(Object o);
// Bulk Operations
boolean containsAll(Collection<?> c);
boolean addAll(Collection<? extends E> c);
boolean removeAll(Collection<?> c);
boolean retainAll(Collection<?> c);
boolean equals(Object o);
int hashCode();
}
相关推荐
java 中 Iterator 与Iterable的作用;java语言需要更多基础沉淀,扎扎实实,后面的各种项目都会如何天翼。进行更高阶的用法和一些框架的原理都离开最基础的东西,基础虽然枯燥,但是也很有乐趣。
今天小编就为大家分享一篇对Python中Iterator和Iterable的区别详解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
Iterator和Iterable 学习任何类和文档最标准的解释当然还是从jdk API里面学习,因为这个是最准确不过的东西了。想看API文档 Iterable java.lang包中 并且Collection继承了Iterable接口。 原创文章 3获赞 10访问量 ...
下面小编就为大家带来一篇java集合_浅谈Iterable和Iterator的区别。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
在本文中小编给大家分享了关于Java中Iterable与Iterator的用法知识点内容,有兴趣的朋友们可以学习下。
一个iterator_jsonDemo. 1.通过iterable接口和iterator实现迭代输出。2.通过JSONArray实现输出(自带json相关jar包)。供参考。
在Python中可迭代(Iterable)、迭代器(Iterator)和生成器(Generator)这几个概念是经常用到的,初学时对这几个概念也是经常混淆,现在是时候把这几个概念搞清楚了。 0x00 可迭代(Iterable) 简单的说,一个对象(在...
详解ES9的新特性之异步遍历... 根据ES6的定义,iteration主要由三部分组成: Iterable 先看下Iterable的定义: interface Iterable { [Symbol.iterator]() : Iterator; } Iterable表示这个对象里面有可遍历的
在开始文章之前,先贴上一张Iterable、Iterator与Generator之间的关系图: 1. Iterator VS Iterable 迭代器(Iterator) 迭代器是实现了迭代器协议的类对象,迭代器协议规定了迭代器类必需定义__next()__方法。当...
前言 Python生成器(generator)并不是一...1. Iterator与Iterable 首先明白两点: Iterator(迭代器)是可迭代对象; 可迭代对象并不一定是Iterator; 比较常见的数据类型list、tuple、dict等都是可迭代的,属于collecti
刚接触到迭代器,生成器的时候常常分不清这些概念的区别,下面的一张图很好的展示了他们的关系: 也就是: 父类 子类 iterable iterator,一些container container list, set, dict iterator generator ...
文章目录Iterable源码分析(一)简介(二...当然,一个类如果没有实现Iterable接口,也可以通过挂载外部迭代器Iterator进行遍历。 此外,内部迭代器还可转换为可分割迭代器Spliterator,以便用于流式操作 注意区别于外
$ npm install node-iterator 例子 import NodeIterator from 'node-iterator' ; // manual iteration let node ; for ( node of NodeIterator ( document . body ) ) { console . log ( node . nodeName ) ; } //...
树迭代器后序行走树的迭代器用法 var PostOrderTree = require ( 'tree-...for(可迭代的var节点)iter = iterable[Symbol.iterator]()iterable.on('cycle', cb)例子对于..of var PostOrderTree = require ( 'tree-
JavaScript的异步迭代器 AsyncIterator是需求驱动的对象流的轻量级JavaScript实现,并且是双向流控制的的替代方法。 与Stream相对,您不能将任何内容推送到Async... 与Iterable一样, AsyncIterator仅在您要求时才
变电站自动化系统中嵌入式Web服务器的设计与实现__EI收录论文报告
注意区别于内部迭代器Iterable和枚举器Enumeration 外部迭代器的设计背后体现着迭代器设计模式的思想 (二)源码分析 该接口就只有四种方法 // 是否存在未遍历元素 boolean hasNext(); // 返回下一个元素
iter(iterable) 从可迭代对象中返回一个迭代器,iterable必须是一个能提供迭代器的可迭代对象 next(iterator) 从迭代器iterator中获取下一条记录,如果无法获取下一条记录,则触发StopIteration 异常 说明: 迭代器...