这篇文章主要看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="#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 = 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 = 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="#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 = 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 = 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源码解析(四)的更多相关文章

  1. ArrayList源码解析

    ArrayList简介 ArrayList定义 1 public class ArrayList<E> extends AbstractList<E> implements L ...

  2. 顺序线性表 ---- ArrayList 源码解析及实现原理分析

    原创播客,如需转载请注明出处.原文地址:http://www.cnblogs.com/crawl/p/7738888.html ------------------------------------ ...

  3. 面试必备:ArrayList源码解析(JDK8)

    面试必备:ArrayList源码解析(JDK8) https://blog.csdn.net/zxt0601/article/details/77281231 概述很久没有写博客了,准确的说17年以来 ...

  4. ArrayList源码解析(二)

    欢迎转载,转载烦请注明出处,谢谢. https://www.cnblogs.com/sx-wuyj/p/11177257.html 自己学习ArrayList源码的一些心得记录. 继续上一篇,Arra ...

  5. Mybatis源码解析(四) —— SqlSession是如何实现数据库操作的?

    Mybatis源码解析(四) -- SqlSession是如何实现数据库操作的?   如果拿一次数据库请求操作做比喻,那么前面3篇文章就是在做请求准备,真正执行操作的是本篇文章要讲述的内容.正如标题一 ...

  6. Java中的容器(集合)之ArrayList源码解析

    1.ArrayList源码解析 源码解析: 如下源码来自JDK8(如需查看ArrayList扩容源码解析请跳转至<Java中的容器(集合)>第十条):. package java.util ...

  7. Sentinel源码解析四(流控策略和流控效果)

    引言 在分析Sentinel的上一篇文章中,我们知道了它是基于滑动窗口做的流量统计,那么在当我们能够根据流量统计算法拿到流量的实时数据后,下一步要做的事情自然就是基于这些数据做流控.在介绍Sentin ...

  8. Collection集合重难点梳理,增强for注意事项和三种遍历的应用场景,栈和队列特点,数组和链表特点,ArrayList源码解析, LinkedList-源码解析

    重难点梳理 使用到的新单词: 1.collection[kəˈlekʃn] 聚集 2.empty[ˈempti] 空的 3.clear[klɪə(r)] 清除 4.iterator 迭代器 学习目标: ...

  9. ArrayList源码解析--值得深读

    ArrayList源码解析 基于jdk1.8 ArrayList的定义 类注释 允许put null值,会自动扩容: size isEmpty.get.set.add等方法时间复杂度是O(1): 是非 ...

  10. 【源码解析】- ArrayList源码解析,绝对详细

    ArrayList源码解析 简介 ArrayList是Java集合框架中非常常用的一种数据结构.继承自AbstractList,实现了List接口.底层基于数组来实现动态容量大小的控制,允许null值 ...

随机推荐

  1. 关于block使用的几点注意事项

    1.在使用block前需要对block指针做判空处理. 不判空直接使用,一旦指针为空直接产生崩溃. if (!self.isOnlyNet) { if (succBlock == NULL) { // ...

  2. 基于Flink的windows--简介

    新的一年,新的开始,新的习惯,现在开始. 1.简介 Flink是德国一家公司名为dataArtisans的产品,2016年正式被apache提升为顶级项目(地位同spark.storm等开源架构).并 ...

  3. net.sz.framework 框架 登录服务器架构 单服2 万 TPS(QPS)

    前言 无论我们做什么系统,95%的系统都离不开注册,登录: 而游戏更加关键,频繁登录,并发登录,导量登录:如果登录承载不起来,那么游戏做的再好,都是徒然,进不去啊: 序言 登录所需要的承载,包含程序和 ...

  4. 利刃 MVVMLight 6:命令基础

    在MVVM Light框架中,事件是WPF应用程序中UI与后台代码进行交互的最主要方式,与传统方式不同,mvvm中主要通过绑定到命令来进行事件的处理, 因此要了解mvvm中处理事件的方式,就必须先熟悉 ...

  5. win8.1启用ahci后蓝屏

    先简单介绍一下,本应该win7开始,系统安装的时候默认就启用了ahci硬盘模式.但是博主犯了傻,装了win8.1后安装win XP形成双系统.xp并不支持ahci模式,所以将硬盘模式改成了IDE模式, ...

  6. Ubuntu下安装Tomcat7

    第一部分:基本安装 1.打开http://tomcat.apache.org/download-70.cgi,下载apache-tomcat-7.0.68.zip. 2.拷贝至合适位置,如/usr/l ...

  7. 概念学习 - JNDI, JDBC, ODBC, DataSource

    layout: post title: 概念学习 - JNDI, JDBC, ODBC, DataSource --- 最近在学习Java Hibernate,对数据库资源访问这块好多概念模糊,所以在 ...

  8. Java数据类型及运算

    (一),Java基本类型及运算 注释:可以用于生成API: 命令如:javadoc -d apidoc windowtitle hhh -doctitle aaa  -header bbbb -ver ...

  9. mysql行列转换方法总结

    这是一道行转列并且构造交叉表的问题: http://topic.csdn.net/u/20090530/23/0b782674-4b0b-4cf5-bc1a-e8914aaee5ab.html 数据样 ...

  10. Unity SLua 如何调用Unity中C#方法

    1.原理 就是通常在Lua框架中所说的,开放一个C#的web接口,或者叫做在Slua框架中注册函数. 2.作用 在Lua中调用C#中的方法,这个是在做热更新中很常用的一种方法,无论是slua,还是lu ...