首页 > 代码库 > ArrayList源码解析(四)

ArrayList源码解析(四)

 

这篇文章主要看ArrayList的Iterator和ListIterator的实现。

1.Iterator和类Itr

当我们调用iterator方法时返回一个Iterator。

   /**     * Returns an iterator over the elements in this list in proper sequence.     *     * <p>The returned iterator is <a href="http://www.mamicode.com/#fail-fast"><i>fail-fast</i></a>.     *     * @return an iterator over the elements in this list in proper sequence     */    public Iterator<E> iterator() {        return new Itr();    }

 

而iterator()方法返回的Iterator是由一个私有类向上转型得到的:

   /**     * An optimized version of AbstractList.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;        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)    //lastRet初值为-1,在没有调用过next()方法保持为-1,不是任何元素的索引;调用一次remove()方法之后为-1,也就是说不能连续调用remove()方法                throw new IllegalStateException();            checkForComodification();            try {                ArrayList.this.remove(lastRet);                cursor = lastRet; //要移除的最近返回的元素,lastRet指向最近返回的元素,而cursor指向下一个要返回的元素,移除了一个元素,自然指向lastRet位置
                lastRet = -1;                expectedModCount = modCount;            } catch (IndexOutOfBoundsException ex) {                throw new ConcurrentModificationException();            }        }        @Override        @SuppressWarnings("unchecked")        public void forEachRemaining(Consumer<? super E> consumer) {            Objects.requireNonNull(consumer);            final int size = ArrayList.this.size;            int i = cursor;            if (i >= size) {                return;            }            final Object[] elementData = http://www.mamicode.com/ArrayList.this.elementData;            if (i >= elementData.length) {                throw new ConcurrentModificationException();            }            while (i != size && modCount == expectedModCount) {                consumer.accept((E) elementData[i++]);     //对元素执行指定的操作,遍历i之后的所有元素            }            // update once at end of iteration to reduce heap write traffic            cursor = i;   //退出上面的while循环时,i等于size            lastRet = i - 1;            checkForComodification();        }        final void checkForComodification() {            if (modCount != expectedModCount)                throw new ConcurrentModificationException();        }    }

 

Itr()里定义了三个变量:

   int cursor;       // index of next element to return   int lastRet = -1; // index of last element returned; -1 if no such   int expectedModCount = modCount;

  cursor 下一个将要返回的元素的索引;

  lastRet 最近(上一个)返回的元素的索引,-1表示最近的一次操作没有返回元素。

  expectedModCount前面提到过。

 

Itr类实现了next()、hasNext()、remove()和forEachRemaining(Consumer<? super E> consumer)方法:

hasNext()

        public boolean hasNext() {            return cursor != size;        }

在next()返回的是cursor指向的元素,所以它不为size时表示还有下一个元素,即调用next()还可以返回元素。

 

next()

     @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];        }

 

checkForComodification()

 final void checkForComodification() {            if (modCount != expectedModCount)                throw new ConcurrentModificationException();        }

用来检查modCount是否等于expectedModCount,前文提到过,这里不再赘述。

 

next()

        @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];        }

主要就是返回cursor指向的元素,然后cursor加1,并令lastRet=i,使其指向最近返回的元素。

 

remove()

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

Remove使用了lastRet的值

注意这里是调用ArrayList的remove实现移除元素的,并使cursor=lastRet,因为移除了一个元素,调用next()返回的元素就位于lastRet了。

lastRet赋值为-1,因为这次操作没有返回元素。

因为修改了elementData的结构,所以需要expectedModCount=modCount。

 

forEachRemaining(Consumer<? super E> consumer)

     @Override        @SuppressWarnings("unchecked")        public void forEachRemaining(Consumer<? super E> consumer) {            Objects.requireNonNull(consumer);            final int size = ArrayList.this.size;            int i = cursor;            if (i >= size) {                return;            }            final Object[] elementData = http://www.mamicode.com/ArrayList.this.elementData;            if (i >= elementData.length) {                throw new ConcurrentModificationException();            }            while (i != size && modCount == expectedModCount) {                consumer.accept((E) elementData[i++]);            }            // update once at end of iteration to reduce heap write traffic            cursor = i;            lastRet = i - 1;            checkForComodification();        }

注意@Override注解,表明这覆盖了父接口的方法。

这个方法就是对从cursor指向的元素开始到集合的最后一个元素,调用consumer.accept()方法进行指定的处理。

调用完这个方法后,cursor值为size,指向所有元素之后,lastRet指向了集合的最后一个元素。

2.ListIterator和类ListItr

当我们调用listIterator()方法时返回一个ListIterator:

    /**     * Returns a list iterator over the elements in this list (in proper     * sequence).     * <p>The returned list iterator is <a href="http://www.mamicode.com/#fail-fast"><i>fail-fast</i></a>.     * @see #listIterator(int)     */    public ListIterator<E> listIterator() {        return new ListItr(0);    }

而listIterator()的返回的ListIterator是由类ListItr向上转型得到的:

    /**     * An optimized version of AbstractList.ListItr     */    private class ListItr extends Itr implements ListIterator<E> {        ListItr(int index) {            super();            cursor = index;        }        public boolean hasPrevious() { return cursor != 0;   }        public int nextIndex() {   return cursor;      }        public int previousIndex() {   return cursor - 1;  }        @SuppressWarnings("unchecked")        public E previous() {            checkForComodification();            int i = cursor - 1;            if (i < 0)                throw new NoSuchElementException();            Object[] elementData = http://www.mamicode.com/ArrayList.this.elementData;            if (i >= elementData.length)                throw new ConcurrentModificationException();            cursor = i;            return (E) elementData[lastRet = i];        }        public void set(E e) {            if (lastRet < 0)                throw new IllegalStateException();            checkForComodification();            try {                ArrayList.this.set(lastRet, e);            } catch (IndexOutOfBoundsException ex) {                throw new ConcurrentModificationException();            }        }        public void add(E e) {            checkForComodification();            try {                int i = cursor;                ArrayList.this.add(i, e);                cursor = i + 1;                lastRet = -1;                expectedModCount = modCount;            } catch (IndexOutOfBoundsException ex) {                throw new ConcurrentModificationException();            }        }    }

 

我们先看ListItr类的带一个参数的构造函数:

     ListItr(int index) {            super();            cursor = index;        }

这个构造函数先调用父类的构造函数建立一个迭代器,然后将index赋给游标cursor。通过这种方式,可以建立了一个指向集合中任意元素的迭代器

注意,Itr中的游标cursor被初始化为0,指向集合中的第一个元素,调用iterator()方法并不能创建指向集合中任意元素的迭代器

 

从源代码中我们可以看到,ListItr并没有重新实现Itr中已经实现的方法,直接从父类Itr中继承过来,比如hasNext()、next()、remove()和forEachRemaining()

要理解next和previous相关的方法,先要认识到,在这里只说下一个元素、前一个元素,而不说当前元素,cursor指向的位置就是下一个元素的位置,这样下面的内容就容易理解了。

 

hasPrevious()

     public boolean hasPrevious() {            return cursor != 0;        }

hasNext()判断的是cursor不等于size,是最后一个元素之后的位置;

而hasPrevious()方法判断的是cursor不等于0,是第一个元素的位置,它之前不再有元素。

 

nexIndex()和previousIndex()

        public int nextIndex() {            return cursor;        }        public int previousIndex() {            return cursor - 1;        }

nextIndex()返回的是调用next()返回的元素的索引,previousIndex()返回的是此时调用previous()返回的索引。

 

previous()

        @SuppressWarnings("unchecked")        public E previous() {            checkForComodification();            int i = cursor - 1;            if (i < 0)                throw new NoSuchElementException();            Object[] elementData = http://www.mamicode.com/ArrayList.this.elementData;            if (i >= elementData.length)                throw new ConcurrentModificationException();            cursor = i;            return (E) elementData[lastRet = i];        }

checkForComodification()是从类Itr继承来的,对结构是否被修改做判断;再判断i的范围,注意cursor可以取到size。
正常情况下,i的值肯定不会大于等于elementData.length这个值。
其实这里就是将cursor减1,然后返回cursor位置的元素,再将lastRet指向刚刚返回的元素的位置。

从这里我们可以看出,lastRet可能小于或等于cursor,但一定不会大于

向前移动的时候,cursor大于lastRet;

反向移动的时候,cursor等于lastRet。

 

set(E e)

        public void set(E e) {            if (lastRet < 0)                throw new IllegalStateException();            checkForComodification();            try {                ArrayList.this.set(lastRet, e);            } catch (IndexOutOfBoundsException ex) {                throw new ConcurrentModificationException();            }        }

替换的元素是lastRet位置的元素,而lastRest永远指向最近一次返回的元素。

 

add(E e)

        public void add(E e) {            checkForComodification();            try {                int i = cursor;                ArrayList.this.add(i, e);                cursor = i + 1;                lastRet = -1;                expectedModCount = modCount;            } catch (IndexOutOfBoundsException ex) {                throw new ConcurrentModificationException();            }        }

add(E e)方法注意新元素插入的位置是在cursor之后就可以了,但是插入新元素之后,cursor加了1,也就是说add之后紧接着调用next()方法,返回的是add的元素

插入新元素之后,lastRet赋值为-1,因为最近没有元素返回

 

ArrayList源码解析(四)