【Java底层】- list迭代器体系

1.迭代器体系介绍:

在这里插入图片描述
AbstractList类中的迭代器为目标,分析迭代器主要的实现和继承:

  1. Iterator:作用在集合上的最底层接口
  2. ListIterator:作用在list上的迭代器,继承Iterator类。根据list的特点,新增了set、add、previous等方法。
  3. AbstractList内部定义了两个私有的迭代器:
    3.1 Itr:实现Iterator接口,定义了Iterator接口方法的实现逻辑。
    3.2 ListItr:继承Itr类、实现ListIterator接口,定义了ListIterator接口方法的实现逻辑。

ArrayList作为AbstractList的子类,也自定了两个内部迭代器,所以ArrayList调用的是自身的迭代器,但方法的实现逻辑是相同的。文章仅分析AbstractList的迭代器方法及实现,其他子类类同。

2. 迭代器调用方法

AbstractList主要有3个调用迭代器方法:

  1. iterator() :返回Iterator迭代器
  2. listIterator():返回listIterator迭代器
  3. listIterator(final int index) :返回特定位置后的集合元素的迭代器
#迭代器调用源码:
public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
    public Iterator<E> iterator() {// 返回迭代器
        return new Itr();
    }   
    
     public ListIterator<E> listIterator() { // 返回迭代器
        return listIterator(0);
    }
    
     public ListIterator<E> listIterator(final int index) {// 返回特定位置之后的迭代器
        rangeCheckForAdd(index);
        return new ListItr(index);
    } 
}    

3.迭代器详解

3.1 Iterator接口

Iterator类是作用在集合上的最底层接口,仅仅定义了4个接口方法:hasNext()、next()、remove()、forEachRemaining

 #Iterator接口源码
public interface Iterator<E> {
    boolean hasNext(); 
    E next();
    default void remove() { 
        throw new UnsupportedOperationException("remove");
    }
    default void forEachRemaining(Consumer<? super E> action) {
        Objects.requireNonNull(action);
        while (hasNext())
            action.accept(next());
    }
}

3.2 ListIterator接口

ListIterator类是作用在list上的迭代器,继承Iterator。
依据list集合特点(索引位置可以确定集合元素),在Iterator基础上新增几类方法:

  1. next返回值的下标索引:nextIndex
  2. next返回值的上一个元素相关信息:hasPrevious、previous、previousIndex
  3. 迭代器中元素的新增和替换:add、set
 #ListIterator源码
public interface ListIterator<E> extends Iterator<E> {
    boolean hasNext();
    E next();
    boolean hasPrevious();
    E previous();
    int nextIndex();
    int previousIndex();
    void remove();
    void set(E e);
    void add(E e);

3.3 Itr和ListItr类

Itr和ListItr类是AbstractList中的两个内部私有类,分别实现了Iterator和ListIterator类中的方法。

3.1 Itr类

Itr实现Iterator接口,定义了两个指针和一个计数器,分别用于迭代循环和是线程同步的问题:

  1. cursor:数组指针
  2. lastRet:上一次调用next或previous时的元素下标
  3. expectedModCount:修改次数

Itr实现了hasNext、next、remove方法的处理逻辑:

  1. next:先返回指针元素值,然后指针下移
  2. hasNext:指针位置是否越界
  3. remove:调用list.remove方法,指针上移;lastRet设为-1,保证remove只能调用一次。

方法调用时,先调用checkForComodification方法,保证list的修改次数与迭代器的相同,所以在调用迭代器时不能对list进行修改操作。

方法处理逻辑结束后,进行expectedModCount==moCount,保证修改次数的一致性。

public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
    protected transient int modCount = 0;// 记录list对象修改次数,list 每修改一次,modCount加1
    #Itr源码
    private class Itr implements Iterator<E> {
        int cursor = 0;// 指针位置
        int lastRet = -1;// 最后一次调用next或previous时,返回值所在的位置。如果调用remove时,lastRet=-1,保证了remove只能被调用一次。
        int expectedModCount = modCount; //修改次数,初始值等于list的modCount。不管调用迭代器中的任何方法,必须保证 expectedModCount = modCount
        final void checkForComodification() {// 检查迭代器的修改次数是否与list的修改次数相等。
        // 如果不相等则抛出异常。所以在Itr类不允许迭代器循环时修改list的元素:while (itr.hasNext()) { itr.next(); arr.add("t"); } 此时会报java.util.ConcurrentModificationException错
            if (modCount != expectedModCount) 
                throw new ConcurrentModificationException();
        }
        
        public boolean hasNext() {// 判断集合是否还存在元素
            return cursor != size(); // 关键就是判断指针是否为集合最后端。
        }
        public E next() { // 获取集合的后面元素,实现逻辑:获取指针位置的元素值,指针位置后移一位。
            checkForComodification();// 修改次数判断
            try {
                int i = cursor;
                E next = get(i); // 获取指针位置的元素值,并return
                lastRet = i; // 将LastRet设置为最后一次next获取的元素位置
                cursor = i + 1; // 指针后移
                return next;  // 返回获取的指针元素值
            } catch (IndexOutOfBoundsException e) { 
                checkForComodification();
                throw new NoSuchElementException();
            }
        }
        public void remove() { // 删除最后一次next或previous时的元素,实现逻辑:调用list.remove(lastRet)方法,指针上移一位
            if (lastRet < 0) // 保证了一个next或previous方法后只能调用一次 remove方法。
                throw new IllegalStateException();
            checkForComodification();  // 修改次数判断
            try {
                AbstractList.this.remove(lastRet); // 调用list的remove方法删除最后一次next或previous时的元素
                if (lastRet < cursor)
                    cursor--; // 指针上移一位
                lastRet = -1; // lastRet设置为 -1,从而限制remove只能操作一次
                expectedModCount = modCount; // 重新设置修改次数,保证与list中的修改次数一致。
            } catch (IndexOutOfBoundsException e) {
                throw new ConcurrentModificationException();
            }
        }
    }
}

3.2ListItr类

ListItr类继承Itr类、实现ListIterator接口,实现了add、set、previous等方法逻辑:

  1. previous:指针先上移一位,再获取指针元素值
  2. add、set:调用list对应方法,lastRet 赋值:lastRet=-1;保证方法只能调用一次。
  3. nextIndex、previousIndex:分别获取指针位置或指针上一个位置的索引下标。

同Itr类原理相同,方法调用时先调用checkForComodification( )方法进行检查,最后保证expectedModCount==moCount。

在调用迭代器时不能对list对象进行修改操作;add、set、remove只能调用一次。

public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
    protected transient int modCount = 0;// 记录list对象修改次数,list 每修改一次,modCount加1
    #ListItr源码
    private class Itr implements Iterator<E> {
        int cursor = 0;// 指针位置
        int lastRet = -1;// 最后一次调用next或previous时,返回值所在的位置。如果调用remove时,lastRet=-1,保证了remove只能被调用一次。
        int expectedModCount = modCount; //修改次数,初始值等于list的modCount。不管调用迭代器中的任何方法,必须保证 expectedModCount = modCount
        final void checkForComodification() {// 检查迭代器的修改次数是否与list的修改次数相等。
            if (modCount != expectedModCount) 
                throw new ConcurrentModificationException();
        }
       ...
    }
    
    private class ListItr extends Itr implements ListIterator<E> {
        ListItr(int index) { // 构造方法,获取从特定位置开始的迭代器
            cursor = index;
        }
        public boolean hasPrevious() { // 判断集合前面是否还有元素
            return cursor != 0;
        }
        public E previous() { // 获取集合前面的元素,实现逻辑:指针上移一位,获取指针位置的元素值
            checkForComodification(); // 保证修改次数相等
            try {
                int i = cursor - 1; // 指针上移一位
                E previous = get(i); // 获取指针所在位置的元素
                lastRet = cursor = i; // 赋值
                return previous; // 返回上一位的元素值
            } catch (IndexOutOfBoundsException e) {
                checkForComodification();
                throw new NoSuchElementException();
            }
        }
        public int nextIndex() { // 获取指针位置索引
            return cursor;
        }
        public int previousIndex() { //获取指针前一个位置索引
            return cursor-1;
        }
        public void set(E e) { // 将最后一次调用next或previous时的位置重新赋值,实现逻辑:调用list.set(lastRet, e)重新赋值。
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();
            try {
                AbstractList.this.set(lastRet, e); // 调用list.set(lastRet, e)重新赋值
                expectedModCount = modCount;// 修改次数
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }
        public void add(E e) {// 添加元素,实现逻辑:调用list.add(i, e)添加元素,指针后移一位
            checkForComodification();
            try {
                int i = cursor;
                AbstractList.this.add(i, e); // 调用list.add(i, e)添加元素
                lastRet = -1; // lastRet设置为-1,保证next或previos后只能调用一次add方法
                cursor = i + 1; // 指针后移一位
                expectedModCount = modCount; // 保证修改次数相等
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }
    }
}    

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值