这篇文章主要看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. 关闭discuzX3.2注册页面的注册邮箱验证

    论坛升级后发现注册用户在输入任何邮箱email时,一直提示email 地址无效.用firephp跟踪发现:随机生成的email的后缀是@localhost! 找到原因,修改如下: //原来代码 if( ...

  2. MongoDB数据库安装及配置环境终极教程(windows10系统)

    本文是笔者花时间踩坑踩生气了写出来的!转载请注明出处@http://www.cnblogs.com/tim100/!请尊重我的劳动成果!谢谢! 今天,给大家说说在windows10系统下MongoDB ...

  3. Ubuntu 重装 mysql

    我另篇blog有提到修改完my.cnf文件后mysql server重新启动失败,就是说mysql server启动不起来了,于是我就想到重装再试试,没想到就好了. 重装mysql之前需要卸载干净,删 ...

  4. Sql server DATEADD日期函数的使用

    DATEADD日期函数 DATEADD() 函数在日期中添加或减去指定的时间间隔. 日:在当前日期上加两天 , ,'2014-12-30') 月:在当前日期上加两个月 , , 年:在当前日期上加两年 ...

  5. UEFI+GPT下安装Win10+Ubuntu16.04双系统

    安装环境 SSD+HDD双盘,Win10安装在SSD里,HDD分出来60G安装Ubuntu. 自行百度你的主板是否支持UEFI启动方式. Win10 下载Win10安装镜像.烧盘等步骤就不说了,重启后 ...

  6. vim粘贴代码问题

    vim粘贴代码问题 vim 在使用xshell进行vim操作的时候,经常会直接粘贴一些外部的代码,然后粘贴上之后会出现逐行缩进的情况,之前一直没有去找为啥,并且逐行的给他弄回去. 转自:https:/ ...

  7. APP自识别安卓苹果

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  8. C#小知识点记录(QQ交流群的一个小问题)Linq提取数据

    请教 这里 LINQ想 找到 最后的 4条 记录 然后放在 这里这个 List Linq查找怎么写呀? 解答:写了一个小例子作为解答. namespace C_Sharp { class Progra ...

  9. C# 调用C++dll出现的问题。

    问题描述: 对 PInvoke 函数“winform应用!winform应用.Form1::add”的调用导致堆栈不对称.原因可能是托管的 PInvoke 签名与非托管的目标签名不匹配.请检查 PIn ...

  10. CF Manthan, Codefest 16 G. Yash And Trees 线段树+bitset

    题目链接:http://codeforces.com/problemset/problem/633/G 大意是一棵树两种操作,第一种是某一节点子树所有值+v,第二种问子树中节点模m出现了多少种m以内的 ...