Java设计模式(迭代器模式 - 概念及jdk迭代器解析)
程序员文章站
2022-06-19 15:14:19
学习设计模式不光要学习设计模式的思想,还要去深入理解,为什么要用这个设计模式。如何深入理解?读优秀的框架代码,看别人代码,了解它们的使用场景。 - - - 博主老师(感谢他)本文先介绍了迭代器模式的概念,并介绍了jdk中的迭代器源码,最后聊了下为什么需要迭代器模式。迭代器模式1、概念2、jdk中的迭代器3、为什么要有迭代器模式1、概念定义:提供一种方法顺序访问一个容器使用场景:遍历一个容器对象。对于开发者来说,几乎不会自己去实现一个迭代器。因为jdk已经帮我们实现好了。我们主要是对....
学习设计模式不光要学习设计模式的思想,还要去深入理解,为什么要用这个设计模式。
如何深入理解?读优秀的框架代码,看别人代码,了解它们的使用场景。 - - - 博主老师(感谢他)
本文先介绍了迭代器模式的概念,并介绍了jdk中的迭代器源码,最后聊了下为什么需要迭代器模式。
迭代器模式
1、概念
定义:提供一种方法顺序访问一个容器
使用场景:遍历一个容器对象。
对于开发者来说,几乎不会自己去实现一个迭代器。因为jdk已经帮我们实现好了。我们主要是对迭代器模式做个了解,看看Java中是怎么去实现迭代器模式的。
2、jdk中的迭代器
我们遍历一个list的时候,经常会用到foreach,如下
public class Test {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("1");
list.add("2");
list.add("3");
for (String aList : list) {
System.out.println(aList);
}
}
}
将Test类,javac一下,生成class文件,再拖到Intellij IDEA中,发现变成了Iterator的方式。
我们重点看下ArrayList的迭代器是怎么实现的
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable { public Iterator<E> iterator() { return new Itr(); } }
iterator方法返回了一个Itr类
首先Itr类实现了Iterator接口
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());
}
}
接下来看Itr
private class Itr implements Iterator<E> { // next方法返回的元素的下标 int cursor; // index of next element to return // 最近一次调用next返回元素的下标(默认-1) int lastRet = -1; // index of last element returned; -1 if no such int expectedModCount = modCount; // 判断是否还有元素,通过游标是否等于size判断 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; // 我们知道,arrayList是通过数组实现的 return (E) elementData[lastRet = i]; } // 删除一个元素 public void remove() { if (lastRet < 0) throw new IllegalStateException(); checkForComodification(); try { // 移除的是上一次next返回的元素 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; // 从cursor开始 int i = cursor; if (i >= size) { return; } final Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) { throw new ConcurrentModificationException(); } // 对cursor - (size-1)的元素做处理,处理的行为是入参定义的函数 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(); } }
3、为什么要有迭代器模式
对于容器对象的访问,必然会涉及遍历算法。如果将遍历封装到容器中,对于容器来说,承担的功能有点多。如果让用户自己实现,那又必须暴露容器的内部实现。所以使用迭代器模式,在客户访问类与容器体之间插入一个第三者-迭代器。
而且Java Iterator统一了迭代方法,不管是list,还是map,或者set等,都可以用Iterator遍历。
https://blog.csdn.net/u010647035/article/details/79826457