目录

​* Iterable #Iterator​

​* Iterator #foreach ​

​* ArrayList # Itr ​

​* ArrayList # Itr # 成员变量​

​* ArrayList # Itr # hasNext​

​* ArrayList # Itr # next​

​* ArrayList # Itr # remove​


* 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();
}
}