前言:

  Iterator翻译过来就是迭代器的意思。在前面的工厂模式中就介绍过了iterator,不过当时介绍的是方法,现在从Iterator接口的设计来看,似乎又是一种设计模式,下面我们就来讲讲迭代器模式到底是怎么实现的。

一、定义

  提供一种方法,顺序访问一个集合对象中的各个元素,而又不暴露该对象的内部表示。(可以理解为遍历)

二、适用场景

1、访问一个集合对象的内容而无需暴露它的内部表示

2、为遍历不同的集合结构提供一个统一的接口

  重要的是对第二点的理解,前面我们在工厂方法中讲过iterator是个工厂方法,Iterator是个产品总接口。对于我们需要的是Iterator这个产品,产品的功能是遍历,我们并不关心这个产品里面存储的结构是List还是Map,不同存储结构的遍历实现应该交给下面的不同的工厂去实现。这里同样也可以这么理解。但是,我们今天讲的是迭代器模式。工厂模式是创建型,而这个模式是行为型。在这里我们或许可以先抛开工厂模式,来去理解这个迭代器模式。

三、结合Iterator接口看迭代器

迭代器模式的角色构成

 1、迭代器(Iterator):定义访问和遍历元素的接口。

 2、具体迭代器(ConcreteIterator ):具体迭代器,实现了迭代器接口,内部会具体实现如何遍历当前聚合。

 3、聚合(Aggregate):内部创建相应迭代器接口的方法。

 4、具体聚合(ConcreteAggregate):内部具体有存储方式以及实现相应迭代器接口,以及一些操作。

  下面我们来结合源码来理解上面4个角色具体是什么样的:

public interface Iterator<E> {

    boolean hasNext();

    E next();

    default void remove() {
throw new UnsupportedOperationException("remove");
} default void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (hasNext())
action.accept(next());
}
}

  上面是迭代器Iterator接口的代码,定义了一些需要子类实现的方法和默认的方法。在这里说一下上面两个default方法都是JDK1.8之后才有的接口新特性,在JDK1.8之前接口中不能有方法实体。

public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
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();
}
} @Override
@SuppressWarnings("unchecked")
public void forEachRemaining(Consumer<? super E> consumer) {
Objects.requireNonNull(consumer);
final int size = ArrayList.this.size;
int i = cursor;
if (i >= size) {
return;
}
final Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length) {
throw new ConcurrentModificationException();
}
while (i != size && modCount == expectedModCount) {
consumer.accept((E) elementData[i++]);
}
// update once at end of iteration to reduce heap write traffic
cursor = i;
lastRet = i - 1;
checkForComodification();
} final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
}

  上面是简化的ArrayList类,因为具体实现迭代器Itr的类在ArrayList中作为内部类存在,这个内部类将接口中的方法做了具体实现,并且是只对ArrayList这个类进行实现的。

public interface List<E> extends Collection<E> {
Iterator<E> iterator();
}

  上面是简化的List接口,充当的是聚合接口,可以看见内部创建了相应迭代器接口的方法。

public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
public Iterator<E> iterator() {
return new Itr();
}
}

  上面是简化的ArrayList类,充当的是具体聚合类角色,在这里是直接返回了一个具体实现迭代器的类。

public class Test1 {

    public static void main(String[] args) {
List<Integer> a=new ArrayList<>();
a.add(1);
a.add(2);
a.add(3);
while(a.iterator().hasNext()){
System.out.println(a.iterator().next());
}
}
}

  这是一个错误的测试类,因为我们每调用一次iterator方法都是会new一个Itr对象,也就是里面的游标会一直重置为0,所以会无限循环。下面才是正确的测试方法

public class Test1 {

    public static void main(String[] args) {
List<Integer> a=new ArrayList<>();
a.add(1);
a.add(2);
a.add(3);
Iterator Itr=a.iterator();
while(Itr.hasNext()){
System.out.println(Itr.next());
}
}
}

四、总结

  平常写代码的时候总会有使用iterator。但是如果要我们自己去动手实现一个集合类的会很少,除非是写框架的时候,大多数我们还是使用为主。当我们需要使用迭代器模式的时候,只需要看上面4个源码的角色扮演和分析,很快就能写出自己的迭代器。前面在适用场景的时候我们是用工厂方法模式来去理解Iterator,但学完这个模式之后,以后的Iterator接口下的实现类,你都可以认为是迭代器模式。因为迭代器模式在各种集合对象中用的实在是太广泛了,所以专门拿这个模式进行源码解释。

结合JDK源码看设计模式——迭代器模式的更多相关文章

  1. 结合JDK源码看设计模式——桥接模式

    前言: 在我们还没学习框架之前,肯定都学过JDBC.百度百科对JDBC是这样介绍的[JDBC(Java DataBase Connectivity,java数据库连接)是一种用于执行SQL语句的Jav ...

  2. 结合JDK源码看设计模式——原型模式

    定义: 指原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象.不需要知道任何创建的细节,不调用构造函数适用场景: 类初始化的时候消耗较多资源 new产生的对象需要非常繁琐的过程 构造函数比较 ...

  3. 结合JDK源码看设计模式——模板方法模式

    前言: 相信很多人都听过一个问题:把大象关进冰箱门,需要几步? 第一,把冰箱门打开:第二,把大象放进去:第三,把冰箱门关上.我们可以看见,这个问题的答案回答的很有步骤.接下来我们介绍一种设计模式--模 ...

  4. 结合JDK源码看设计模式——建造者模式

    概念: 将一个复杂对象的构建与它的表示分离.使得同样构建过程可以创建不同表示适用场景: 一个对象有很多属性的情况下 想把复杂的对象创建和使用分离 优点: 封装性好,扩展性好 详解: 工厂模式注重把这个 ...

  5. 结合JDK源码看设计模式——策略模式

    前言: 现在电商已经成为我们生活中不可或缺的购物渠道,同时各大商家会针对不同的时间做出不同的折扣,这在我们看来就是一种营销手段,也是一种策略,今天我们就来讲讲JDK中的策略模式是怎么样的. 一.定义 ...

  6. 结合JDK源码看设计模式——组合模式

    前言: 相信大家都打开过层级很多很多的文件夹.如果把第一个文件夹看作是树的根节点的话,下面的子文件夹就可以看作一个子节点.不过最终我们寻找的还是文件夹中的文件,文件可以看做是叶子节点.下面我们介绍一种 ...

  7. 结合JDK源码看设计模式——单例模式

    定义: 保证一个类仅有一个实例,并提供一个全局访问点 适用场景: 确保任何情况下这个对象只有一个实例 详解: 私有构造器 单利模式中的线程安全+延时加载 序列化和反序列化安全, 防止反射攻击 结合JD ...

  8. 结合JDK源码看设计模式——简单工厂、工厂方法、抽象工厂

    三种工厂模式的详解: 简单工厂模式: 适用场景:工厂类负责创建的对象较少,客户端只关心传入工厂类的参数,对于如何创建对象的逻辑不关心 缺点:如果要新加产品,就需要修改工厂类的判断逻辑,违背软件设计中的 ...

  9. 结合JDK源码看设计模式——享元模式

    前言 在说享元模式之前,你一定见到过这样的面试题 public class Test { public static void main(String[] args) { Integer a=Inte ...

随机推荐

  1. 3d轮播图(另一种方式,可以实现的功能更为强大也更为灵活,简单一句话,比酷狗优酷的炫)

    前不久我做了一个3d仿酷狗的轮播图,用的技术原理就是简单的jquery遍历+css样式读写. 这次呢,我们换一种思路(呵呵其实换汤不换药),看到上次那个轮播吗?你有没有发现用jquery的animat ...

  2. Java面向对象(二、继承)

    Java 继承 继承的概念 继承是java面向对象编程技术的一块基石,因为它允许创建分等级层次的类. 继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法 ...

  3. Git分支合并冲突解决(续)

    接Git分支合并冲突解决,在使用rebase合并冲突情况下,如果不小心,执行完add后执行了commit,此时本地仓库HEAD处于游离态(即HEAD指向未知的分支),如何解决? 解决方法 (1)此时, ...

  4. 【转】利用 three.js 开发微信小游戏的尝试

    前言 这是一次利用 three.js 开发微信小游戏的尝试,并不能算作是教程,只能算是一篇笔记吧. 微信 WeChat 6.6.1 开始引入了微信小游戏,初期上线了一批质量相当不错的小游戏.我在查阅各 ...

  5. sql语句查询执行顺序

    http://blog.csdn.net/bitcarmanlee/article/details/51004767

  6. MySql常用两大存储引擎简介

    MyISAM存储引擎简介 MyISAM存储引擎的表在数据库中,每一个表都被存放为三个以表名命名的物理文件. 首先肯定会有任何存储引擎都不可缺少的存放表结构定义信息的.frm文件,另外还有.MYD和.M ...

  7. iPhone越狱

    手机越狱 常用工具:PP越狱助手.盘古越狱.iTunes 如果手机第一次越狱使用pp越狱助手成功率比较高 iPhone固件下载地址http://iphone.91.com/fw/iphone5/ 具体 ...

  8. div布局之面向对象

    栗子之导航条(navbar) http://www.runoob.com/try/try2.php?filename=bootstrap-using-glyphicons-navbar <!DO ...

  9. SSM-SpringMVC-23:SpringMVC中初探异常解析器

    ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 本篇博客要讲的是异常解析器,SimpleMappingExceptionResolver简单映射异常解析器 可 ...

  10. JavaScript的垃圾回收机制

    JavaScript语言是一门优秀的脚本语言.其中包含脚本语言的灵活性外还拥有许多高级语言的特性.例如充许构建和实例化一个对象,垃圾回收机制(GC:Garbage Collecation).通常我们使 ...