基于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-2 | Java容器源码攻坚战--第一战:Iterator |
V0.2--无 | - | - |
2.更多关于我
笔名 | 微信 | 爱好 | |
---|---|---|---|
张风捷特烈 | 1981462002 | zdl1994328 | 语言 |
我的github | 我的简书 | 我的CSDN | 个人网站 |
3.声明
1----本文由张风捷特烈原创,转载请注明
2----欢迎广大编程爱好者共同交流
3---个人能力有限,如有不正之处欢迎大家批评指证,必定虚心改正
4----看到这里,我在此感谢你的喜欢与支持
网友评论