ArrayList-Iterator源码分析

2018-01-25  本文已影响0人  Gallrax

此源码分析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
上一篇下一篇

猜你喜欢

热点阅读