Java容器源码攻坚战--第一战:Iterator

mac2022-06-30  102

基于java10.1

零、前言

如果想读读源码测试功力,或读读源码修养身心,或读读源码满足自虐倾向,我建议第一个类是:ArrayList 第一、常用----所以用法比较熟悉,看完源码你也会更明白如何去用 第二、相对简单----1595行代码,刨去注释的一大堆也没有太多,还是hold的住的 第三、还没想好

这篇并不是讲ArrayList,而是Iterator,它是容器以及映射中非常重要的一环

一、迭代器模式

提起设计模式,总是有种只知其形,难达其意的感觉,用三个字说就是高大上

迭代器模式(Iterator),提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露该对象的内部表示。 优势: 它支持以不同的方式遍历一个聚合 迭代器简化了聚合的接口 在同一个聚合上可以有多个遍历 迭代器模式.png
1.适配器接口

最简单的适配器有两个方法hasNext()和next(),这两个方法可以组成一个逻辑链:如果有下一个,取出下一个

/** * 作者:张风捷特烈 * 时间:2018/10/1 0001:23:11 * 邮箱:1981462002@qq.com * 说明:适配器接口 */ public interface Iterator<T> { /** * 是否有下一个元素 * @return 是否有下一个元素 */ boolean hasNext(); /** * 下一个元素 * @return 下一个元素 */ T next(); }
2.聚合对象接口

所谓聚合就是内部含有多个某类型的元素,比如教室和学生的关系,就是聚合对象(教室)与单体元素(学生)的关系

/** * 作者:张风捷特烈 * 时间:2018/10/1 0001:23:17 * 邮箱:1981462002@qq.com * 说明:聚合对象接口 */ public interface Group<T> { /** * 添加元素 * @param el 元素 */ void add(T el); /** * 获取元素 * @param index 索引 * @return 元素 */ T get(int index); /** * 获取迭代器 * @return 迭代器 */ Iterator<T> iterator(); /** * 内部元素总数 * @return 元素总数 */ int size(); }
3.迭代器实现类
/** * 作者:张风捷特烈 * 时间:2018/10/1 0001:23:13 * 邮箱:1981462002@qq.com * 说明:迭代器实现类 */ public class IteratorImpl<T> implements Iterator { //持有聚合对象引用 private Group<T> mGroup; //当前游标指向的索引处 private int curIndex; public IteratorImpl(Group group) { mGroup = group; } @Override public boolean hasNext() { //当游标的指向索引比元素总数少,说明还有next return curIndex < mGroup.size(); } @Override public T next() { //返回当前索引处元素 T el = mGroup.get(curIndex); //当游标的指向索引后移 curIndex++; return el; } }
4.集合对象实现类
/** * 作者:张风捷特烈 * 时间:2018/10/1 0001:23:20 * 邮箱:1981462002@qq.com * 说明:集合对象实现类 */ public class GroupImpl<T> implements Group<T> { //维护一个数组盛放元素 private T[] data; //维护内部元素个数 private int size = 0; public GroupImpl() { //为了简单,使用固定容积50 data = (T[]) new Object[50]; } @Override public void add(T el) { data[size] = el; size++; } @Override public T get(int index) { return data[index]; } @Override public Iterator<T> iterator() { return new IteratorImpl(this); } @Override public int size() { return size; } }
5.测试
public class Client { public static void main(String[] args) { GroupImpl<Student> classRoom = new GroupImpl<>(); classRoom.add(new Student(1, "捷特")); classRoom.add(new Student(2, "龙少")); classRoom.add(new Student(3, "巫缨")); for (int i = 0; i < classRoom.size(); i++) { System.out.println(classRoom.get(i)); } Iterator<Student> it = classRoom.iterator(); // System.out.println(it.next());//Student{id=1, name='捷特'} // System.out.println(it.next());//Student{id=2, name='龙少'} // System.out.println(it.next());//Student{id=3, name='巫缨'} // System.out.println(it.next());//null while (it.hasNext()) { System.out.println(it.next()); // Student{id=1, name='捷特'} // Student{id=2, name='龙少'} // Student{id=3, name='巫缨'} } } } 迭代器模式例.png

二、ArrayList中的Iterator

java中内置的聚合类,顶尖接口Collection实现了Iterable接口,也就是可迭代

1.Iterable接口中定义了获取Iterator对象的函数iterator()
public interface Iterable<T> { Iterator<T> iterator();
2.Collection继承了Iterable接口也必然继承它的方法
public interface Collection<E> extends Iterable<E> { Iterator<E> iterator();
3.同样List接口继承了Collection接口也必然这个方法
public interface List<E> extends Collection<E> { Iterator<E> iterator();
4.java中自带的迭代器: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()); } }
4.该方法在ArrayList中的实现

private class Itr implements Iterator<E>说明该迭代器实现类Itr是ArrayList的内部类 这样做就不必让Itr持有ArrayList的引用,简单一些。

public Iterator<E> iterator() { //返回一个迭代器实现类对象 return new Itr(); } private class Itr implements Iterator<E> { int cursor; // 游标:将要返回的元素索引 int lastRet = -1; // 最后一个被返回元素的索引,-1表示没有返回过 int expectedModCount = modCount;//期望的修改次数与真是修改次数置同 //私有化构造方法 Itr() {} public boolean hasNext() { //当游标未达到元素总数时,表明还有下一个元素 return cursor != size; } @SuppressWarnings("unchecked") public E next() { checkForComodification();//见I--1 int i = cursor;//用变量i暂存游标位置 if (i >= size)//游标位置大于等于size,抛出异常 throw new NoSuchElementException(); //获取当前ArrayList的成员变量:elementData(当前数组) Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length)//游标位置大于当前数组总长,抛出异常 throw new ConcurrentModificationException(); cursor = i + 1;//游标后移 //维护lastRet为i,即返回的元素索引 return (E) elementData[lastRet = i]; } public void remove() { if (lastRet < 0)//即没有调用过next()方法:见Test-1 throw new IllegalStateException(); checkForComodification();//见I--1 try { ArrayList.this.remove(lastRet);//移除操作 cursor = lastRet;//索引指向刚才移除的索引位 lastRet = -1;//最后返回的索引置为-1,[由此可见不能连续执行两次iterator.remove()操作] expectedModCount = modCount;//期望的修改次数与真是修改次数置同 } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } @Override//测试见:Test-2 public void forEachRemaining(Consumer<? super E> action) { Objects.requireNonNull(action);//判断是否为空,空则抛空指针 final int size = ArrayList.this.size;//size记录元素中个数 int i = cursor;//用变量i暂存游标位置 if (i < size) { final Object[] es = elementData;//记录数组 if (i >= es.length)//越界 throw new ConcurrentModificationException(); for (; i < size && modCount == expectedModCount; i++) action.accept(elementAt(es, i));//见I--2 // update once at end to reduce heap write traffic cursor = i; lastRet = i - 1; checkForComodification();///见I--1 } } }
I--1:查看期望修改次数与实际修改次数是否相同
final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); }
I--2:返回一个数组指定索引位置的元素
static <E> E elementAt(Object[] es, int index) { return (E) es[index]; }
Test-1
ArrayList<String> aList = new ArrayList(); aList.add("b"); aList.add("a"); aList.add("c"); Iterator<String> iterator = aList.iterator(); iterator.remove();//直接使用移除会报异常 //Exception in thread "main" java.lang.IllegalStateException ArrayList<String> aList = new ArrayList(); aList.add("b"); aList.add("a"); aList.add("c"); Iterator<String> iterator = aList.iterator(); String first = iterator.next(); System.out.println(first);//b System.out.println(aList);//[b, a, c] //执行过iterator.next(),lastRet指向返回元素的位置,就不再是0,调用remove就不会异常了 iterator.remove();//移除iterator最后返回的元素 System.out.println(aList);//[a, c] Iterator<String> iterator = aList.iterator(); String first = iterator.next(); String second = iterator.next(); System.out.println(first);//b System.out.println(second);//a System.out.println(aList);//[b, a, c] //执行两次iterator.next(),iterator最后返回的元素为a,移除之 iterator.remove(); System.out.println(aList);//[b, c]
Test-2
ArrayList<String> aList = new ArrayList(); aList.add("b"); aList.add("a"); aList.add("c"); Iterator<String> iterator = aList.iterator(); iterator.forEachRemaining(s -> { s += "-Hello"; System.out.print(s+" ");//b-Hello a-Hello c-Hello });

就酱紫,Iterator这个类的用法差不多也就这些


后记:捷文规范

1.本文成长记录及勘误表
项目源码日期备注V0.1--无2018-10-2Java容器源码攻坚战--第一战:IteratorV0.2--无--
2.更多关于我
笔名QQ微信爱好张风捷特烈1981462002zdl1994328语言我的github我的简书我的个人网站
3.声明

1----本文由张风捷特烈原创,转载请注明 2----欢迎广大编程爱好者共同交流 3---个人能力有限,如有不正之处欢迎大家批评指证,必定虚心改正 4----看到这里,我在此感谢你的喜欢与支持

转载于:https://www.cnblogs.com/toly-top/p/9781856.html

最新回复(0)