从头开始学JDK-------Iterator、Iterable

目录

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

 

posted @ 2022-07-17 12:13  小大宇  阅读(14)  评论(0编辑  收藏  举报