美文网首页
ArrayList-Iterator源码分析

ArrayList-Iterator源码分析

作者: Gallrax | 来源:发表于2018-01-25 17:41 被阅读0次

    此源码分析JDK版本为1.7,只是简单分析,算是个人看源码的一点小总结,随意性比较强,专业的还需百度。

    private class Itr implements Iterator<E>{}

    简介

    私有内部类

    private class Itr implements Iterator<E> {}
    

    属性

    //下一个元素返回的索引
    int cursor;
    //遍历上个元素的索引 如果没有则返回-1
    int lastRet = -1;
    //当前修改次数(参考ArrayList的modCount属性)
    int expectedModCount = modCount;
    

    构造方法

    方法

    //判断是否还有下一个
    public boolean hasNext() {
        //通过判断下一个下标是否为数组大小即可得出结果
        return cursor != size;
    }
    //检查当前Itr修改次数和ArrayList是否一致,不一致则抛异常(并发异常) ps:final是防止子类覆盖此方法(ListItr)
    final void checkForComodification() {
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
    }
    //获取下一个元素
    public E next() {
        //检查修改次数是否一致
        checkForComodification();
        //定义i为下个元素的下标
        int i = cursor;
        //下标判断
        if (i >= size)
            throw new NoSuchElementException();
        //定义elementData为ArrayList的数组
        Object[] elementData = ArrayList.this.elementData;
        //再次下标判断,此次判断不一致则说明数组修改过,抛出异常(并发异常)
        //可能出现的场景1.ArrayList的remove()方法中中elementData[--size] = null,size--之前进入了此方法
        if (i >= elementData.length)
            throw new ConcurrentModificationException();
        //定义下个元素的下标
        cursor = i + 1;
        //将lastRet定义为下个元素的下标(返回的最后一个元素的下标),返回该下标对应的值
        return (E) elementData[lastRet = i];
    }
    //移出当前元素
    public void remove() {
        //如果无当前遍历元素则抛出异常
        if (lastRet < 0)
            throw new IllegalStateException();
        //检查修改次数是否一致
        checkForComodification();
    
        try {
            //调用ArrayList的remove方法(如果在遍历外remove会导致Itr中的expectedModCount没有修改抛异常)
            ArrayList.this.remove(lastRet);
            //定义下一个元素的下标为当前下标
            cursor = lastRet;
            //定义上个遍历下标为-1
            lastRet = -1;
            expectedModCount = modCount;
        } catch (IndexOutOfBoundsException ex) {
            throw new ConcurrentModificationException();
        }
    }
    

    private class ListItr extends Itr implements ListIterator<E> {}

    简介

    继承Itr的顺序遍历,自己封装的逆序遍历
    逆序遍历是从构造方法传参的下标开始往上遍历(默认的构造方法传参为0,无法逆序遍历)
    可以说ListItr存在的意义就是逆序遍历、set()和add(),如果不使用逆序遍历完全可以使用Itr

    private class ListItr extends Itr implements ListIterator<E> {}
    

    属性

    继承Itr
    

    构造方法(参数一般为数组的长度)

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

    方法

    //是否拥有上一个元素
    public boolean hasPrevious() {
        return cursor != 0;
    }
    //下一个元素下标
    public int nextIndex() {
        return cursor;
    }
    //上一个元素下标
    public int previousIndex() {
        return cursor - 1;
    }
    //获取上一个元素
    public E previous() {
        //检查修改次数是否一致
        checkForComodification();
        //定义i为上个元素的下标
        int i = cursor - 1;
        //下标判断
        if (i < 0)
            throw new NoSuchElementException();
        //定义elementData为ArrayList的数组
        Object[] elementData = ArrayList.this.elementData;
        //可能出现的场景1.ArrayList的remove()方法中中elementData[--size] = null,size--之前进入了此方法
        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的set方法(如果在遍历外set会导致Itr中的expectedModCount没有修改抛异常)
            ArrayList.this.set(lastRet, e);
        } catch (IndexOutOfBoundsException ex) {
            throw new ConcurrentModificationException();
        }
    }
    //为当前下标后增加值
    public void add(E e) {
        //检查修改次数是否一致
        checkForComodification();
    
        try {
            int i = cursor;
            //调用ArrayList的add方法(如果在遍历外add会导致Itr中的expectedModCount没有修改抛异常)
            ArrayList.this.add(i, e);
            cursor = i + 1;
            lastRet = -1;
            expectedModCount = modCount;
        } catch (IndexOutOfBoundsException ex) {
            throw new ConcurrentModificationException();
        }
    }
    

    总结

    1.在Iterator遍历时,对list进行set操作并不会抛出异常,也就是说存在脏数据问题
    2.ListItr在Itr的基础上增加了逆序遍历、set()和add()
    3.在遍历时对ArrayList的add和remove操作应该使用Itr或者其子类完成,防止出现ConcurrentModificationException
    

    相关文章

      网友评论

          本文标题:ArrayList-Iterator源码分析

          本文链接:https://www.haomeiwen.com/subject/wonmaxtx.html