迭代器源码分析
迭代器源码分析
import java.util.Iterator;
public class Demo2 {
public static void main(String[] args) {
//迭代器源码分析
//创建一个集合并且添加元素
ArrayList<String> list=new ArrayList<>();
list.add("aaa");
list.add("bbb");
list.add("ccc");
/*
* iterator() 生成一个迭代器对象,默认指向集合0索引处
* hasNext() 判断当前指向的位置是否又元素
* next() 1.获取元素 2.移动指针
* */
Iterator<String> it=list.iterator();
while (it.hasNext()){
String str=it.next();
System.out.println(str);
}
}
}
我们知道这个Iterator
首先我们进入iterator()的源码
public Iterator<E> iterator() {
return new Itr();
}
这里可以看到他是创建了一个Itr()的对象进行返回
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;
// prevent creating a synthetic constructor
Itr() {}
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
public void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
final int size = ArrayList.this.size;
int i = cursor;
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));
// update once at end to reduce heap write traffic
cursor = i;
lastRet = i - 1;
checkForComodification();
}
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
我们拆开了阅读
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;
这里可以看到,这里是一个内部类实现了Iterator
定义了三个成员变量
分别表示
第一个:有一个光标的意思,可以理解为指针
第二个:表示上一次索引位置,默认为:-1
第三个:跟并发修改异常有关,待会解释
Itr() {}
当我们使用空参构造创建迭代器的对象的时候,默认指针的索引是0,上一次也就是-1
接下来分析hasNext()方法
public boolean hasNext() {
return cursor != size;
}
这里就是拿到指针0和集合大小进行判断看是否相等,不相等就返回true表示集合中有元素,相等就返回false,表示这个位置没有元素
明显我在集合中添加了三个元素,size=3
接下来看next()方法
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];
}
第一句暂时忽略,待会讲
首先,定义了i等于cursor,可以知道初始是0,表示的是上一次操作索引的位置
接下来走到if语句,明显不满足,这一步其实就是说,如果上一次操作的索引等于了这个size,也就是超出原集合最大索引了,就会报一个异常NoSuchElementException
,这个叫没有这个元素异常
走到Object[] elementData = ArrayList.this.elementData;
我们知道ArraysList底层是数组elemenData,也就是把集合底层数组的地址拿过来赋值给Object[] elementData
,方便下次使用
然后继续判断这一步也暂时忽略
cursor = i + 1;
return (E) elementData[lastRet = i];
关键是这里,首先,把指针往后移动了一个
然后把移动之前也就是0索引位置的元素做了一个返回,最后我们使用str接收,并且做了一个打印
这里就体现出来了,移动指针,并且返回上一次索引中的数据
反复执行一直到 i 表示的是最后一个元素的时候,把指针移动到了数组最外面一个单位,并且将最后一个数据进行返回
如果继续强行移动指针,并且获取下一个元素
if (i >= size)
throw new NoSuchElementException();
就会报NoSuchElementException()
异常
最后我们将一下这个modCount,其实他相当于集合变化的次数
为什么怎么说你,还是扒源码
public boolean add(E e) {
modCount++;
add(e, elementData, size);
return true;
}
public E remove(int index) {
Objects.checkIndex(index, size);
final Object[] es = elementData;
@SuppressWarnings("unchecked") E oldValue = (E) es[index];
fastRemove(es, index);
return oldValue;
}
private void fastRemove(Object[] es, int i) {
modCount++;
final int newSize;
if ((newSize = size - 1) > i)
System.arraycopy(es, i + 1, es, i, newSize - i);
es[size = newSize] = null;
}
我们在add和remove方法中都发现了modCount++,所以就可以证明他是修改次数的意思
这下我们回到next()看第一句执行代码
checkForComodification();
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
这里就可以看到
第一个modCount是集合变化的次数,和创建的时候的次数进行比较,如果不相等,就会发生,并发修改异常ConcurrentModificationException()
,这也是为什么使用迭代器的时候,不能用集合的方式进行增删,这跟next()方法中的第二个判断也就是一个意思,如果使用了集合的方式进行增删,次数肯定不想等,从而引发并发修改异常
所以要使用迭代器自带的增删方式,最后迭代器源码就分析完毕!