来了解下AbstractList

AbstractList是对List接口的最小化实现。和其他抽象集合类的实现不同,我们不需要实现迭代器,因为这个抽象类已经为我们实现了接近于随机访问的迭代器iterator和专门用于list的list iterator。


下面是迭代器的实现:

public Iterator<E> iterator() {
    return new Itr();
}复制代码

在这里它是创建了一个Itr类,它实现了Iterator接口,是AbstractList类的私有内部类。

这个类里面有三个变量:

1. cursor也就是游标变量

2. lastRet变量:它指的是在最近一次调用next方法或者previous方法的时候返回的元素的索引值。当调用remove方法的时候它会被重置为-1。

3.  expectedModCount变量:用来记录期望修改的次数,是迭代器用来检测是否发生了并发的修改操作。


public E next() {
    checkForComodification();
    try {
        int i = cursor;
        E next = get(i);
        lastRet = i;
        cursor = i + 1;
        return next;
    } catch (IndexOutOfBoundsException e) {
        checkForComodification();
        throw new NoSuchElementException();
    }
}复制代码

上面是next方法的实现。从它的实现可以看得出,每调用一次该方法,游标的值就会加1,然后调用get方法获得下一个值,同时把i赋给lastRet。但是在它抽象类中是没有实现get方法,它留给具体的实现类来实现的,所以这是个模板方法。


checkForCommodification方法是用来处理ConcurrentModificationException异常的,当实际修改的次数与期望修改的次数不一样的时候,就说明该集合处于多线程的环境下。

public void remove() {
    if (lastRet < 0)
        throw new IllegalStateException();
    checkForComodification();

    try {
        AbstractList.this.remove(lastRet);
        if (lastRet < cursor)
            cursor--;
        lastRet = -1;
        expectedModCount = modCount;
    } catch (IndexOutOfBoundsException e) {
        throw new ConcurrentModificationException();
    }
}复制代码

上面是迭代器的删除方法。可以看出一个规律是要在调用了next方法之后,才可调用remove方法,删除的元素的索引就是lastRet,而这里真正调用的是抽象类的remove方法,这个方法在抽象类的实现是要抛出不支持该操作的异常,这个删除方法也是要留给它的子类来实现的。

public boolean equals(Object o) {
    if (o == this)
        return true;
    if (!(o instanceof List))
        return false;

    ListIterator<E> e1 = listIterator();
    ListIterator<?> e2 = ((List<?>) o).listIterator();
    while (e1.hasNext() && e2.hasNext()) {
        E o1 = e1.next();
        Object o2 = e2.next();
        if (!(o1==null ? o2==null : o1.equals(o2)))
            return false;
    }
    return !(e1.hasNext() || e2.hasNext());
}
复制代码

上面是2个集合判等的方法。这个方法就利用了ListIterator来进行元素的遍历,判断每个元素是否相等,其中从if判断到最后一句return,这段代码是比较精妙的。首先我们的习惯思维是循环判断2个集合的每一个元素是否相等,往往会在if里面直接去掉!,但这样做实际上为时过早,因为要判定2个集合的元素都相等,需要经过2次的循环才能确定。第一次循环是为了分别得到2个集合里面的元素,第二次遍历是判断是否已经遍历结束,只有遍历结束了才可以返回true或false。而加了!就可以直接返回false了。

ListIterator<E> it = listIterator(fromIndex);
for (int i=0, n=toIndex-fromIndex; i<n; i++) {
    it.next();
    it.remove();
}复制代码

上面是删除某个区间的元素的方法,其中toIndex所指向的元素不被包含进去。若干fromIndex==toIndex那么这个方法就不起作用。可以看出for循环和迭代器都用到了。同时这里也进行了一个小的优化是:计算出要遍历的次数n,儿不是直接用i<toIndex-fromIndex,因为这样会增加循环的时候的运算次数。


最后需要强调的一点是:凡是用到迭代器来进行修改操作,在多线程的环境下回导致同步修改的异常。


下一篇我们会介绍ArrayList的主要部分。由于个人的认知水平有限,如有不正确的地方,欢迎大家指正。



转载于:https://juejin.im/post/5ca9f5b65188254351723045

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值