从头开始学JDK-------Iterator、Iterable
目录
* Iterable #Iterator
天天都在用的for each 语句,背后的原理实际上就是实现了Iterable接口。实现了该接口需要返回一个迭代器。这个迭代的顶层接口就是Iterator。
public interface Iterable<T> ...
Iterator<T> iterator();
* Iterator #foreach
那么foreach语句究竟是怎么工作的呢?原来Iterator接口中提供了3个方法需要实现。
interface Iterator<E> ...
boolean hasNext();
E next();
default void remove() {
throw new UnsupportedOperationException("remove");
}
for(T element : elements) { }
等价于
while(hasNext()) { T element = next(); }
* ArrayList # Itr
ArrayList可能是目前Java界最高频率使用的类之一了。我们在循环ArrayList的时候,都会去使用for each语句。那么,原理到底是什么呢?
ArrayList类实现了Iterable接口,返回了一个迭代器Iterator接口的实现。我们来看一下代码。
class ArrayList<E> implements Iterator<E> ...
public Iterator<E> iterator() {
return new Itr();
}
private class Itr implements Iterator<E> ...
ArrayList实现了Iterable接口后,需要实现iterator方法。这个方法返回值是一个迭代接口,ArrayList内部实现了该接口。
ArrayList是一个动态的数组,内部持有一个 Object[] elementData数组,通过扩容机制可以动态的修改该数组的长度。
对ArrayList进行foreach的时候,相当于调用内部的Iterator对象进行迭代。
for(T element : elements) { }
等价于
while(hasNext()) { T element = next(); }
* ArrayList # Itr # 成员变量
cursor是光标,指向的是准备返回的下一个元素。
lastRet是上一次返回元素的角标,初始化为-1,如果上一个被返回的元素调用remove()方法被删除掉后,lastRet会重置为-1。
expectedModCount与modCount两个参数是用来支持【快速失败】机制的。
【快速失败】是指在迭代ArrayList的时候,不允许在此期间对该ArrayList进行新增或删除元素操作。
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; // fast failure
* ArrayList # Itr # hasNext
这里的size是指ArrayList内部元素Object [] elementData 实际存放的元素个数。
光标cursor如果等于了size,说明迭代器已经迭代过最后一个元素了,这代表没有下一个元素。
class ArrayList ...
private class Itr implements Iterator<E> ...
public boolean hasNext() {
return cursor != size;
}
* ArrayList # Itr # next
检查是否在元素是否在迭代期间,有新增或者删除操作。如果有,需要报错。
这里做一些健壮性判断
(1)判断光标cursor是否超过了size(Object [] elementData 的实际存放元素个数)
(2)判断光标cursor是否超过了size(Object [] elementData 的 length)
然后就是取出elementData数组中对应的元素。
最后并把光标指向下一个元素,并记录返回的元素的角标。至此,ArrayList已经能够支持 foreach语句。
class ArrayList ...
private class Itr implements Iterator<E> ...
public E next() {
//fast failure
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;
lastRet = i
return (E) elementData[i];
}
* ArrayList # Itr # remove
remove方法就是在迭代期间删除迭代的元素。
lastRet是上一次返回元素的角标,如果上一个被返回的元素调用remove()方法被删除掉后,lastRet会重置为-1。
重复调用remove方法会抛出异常。
如果删除第1个元素,那么就把第1个元素的后面所有元素,从第1个元素开始,覆盖掉以前的所有数据。然后把数组最后一个元素置为null。
这里先算出要移动多少个元素,然后把要删除的第N个元素的后面所有的元素,从N个元素开始覆盖。
System.arraycopy(Object src,int srcPos,Object dest, int destPos,int length) ;将源数组src从srcPos索引处,复制length个元素,覆盖目标数组dest。从目标数组dest的destPos处开始覆盖,覆盖目标数组length个元素。
最后会多出一个元素,把它置空即可。
class ArrayList ...
private class Itr implements Iterator<E> ...
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
int numMoved = (size - 1) - lastRet;
if (numMoved > 0)
System.arraycopy(elementData, lastRet+1, elementData, lastRet,
numMoved);
elementData[--size] = null; // clear to let GC do its work
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}