前言:
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 接口下的实现类, 你都可以认为是迭代器模式. 因为迭代器模式在各种集合对象中用的实在是太广泛了, 所以专门拿这个模式进行源码解释.
来源: https://www.cnblogs.com/Cubemen/p/10688624.html