源码分析 - JDK - Iterator.hasNext()/next()/remove()

本文详细解析了ArrayList类中的迭代器实现,包括迭代器的创建、遍历、删除操作及失败快速机制。深入探讨了Itr类的工作原理,以及如何在迭代过程中检查并发修改。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

使用迭代器之前需要先创建,下面是创建迭代器的方法,该方法在ArrayList类中 

    /**
     * Returns an iterator over the elements in this list in proper sequence.
     * 返回一个可以按照适当顺序迭代list中的元素的迭代器
     * 返回的Itr类,该类实现了Iterator<E>接口,属于ArrayList中的内部类
     *
     * <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();
    }

下面是Itr类中的方法详细分析:

    /**
     * An optimized version of AbstractList.Itr Itr的最优版本
     * AbstractList<E>和ArrayList<E>类中都有私有的Itr内部类,这个Itr是ArrayList<E>中
     * 的内部类,也是最理想的一个
     */
    private class Itr implements Iterator<E> {
        int cursor;       // 下一个元素的指针
        int lastRet = -1; // 上一个元素的指针,如果没有元素则是-1
        //期望修改计数器,与修改计数器去比较从而确认迭代期间元素数组是否被修改
        int expectedModCount = modCount; 

        public boolean hasNext() {
            //判断指针是否到达了数组最后一个元素+1的位置,来判断是否还有元素
            return cursor != size;
        }

        @SuppressWarnings("unchecked")
        public E next() {
            checkForComodification(); //同时修改检查函数,最下方详解
            int i = cursor; //定义临时的当前元素的指针i并赋值
            if (i >= size)
                //如果当前指针超出了范围则抛出没有足够元素异常,同理于hasNext()判断
                throw new NoSuchElementException();
            /**
             * 因为该私有类是在ArrayList<E>内部,所以可以直接调用ArrayList类中的属性
             * 该方法要返回元素数组的其中一个内容,在这里获取元素数组
             */
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                //通过直接检查数组的长度,进一步确认数组是否被修改
                throw new ConcurrentModificationException();
            cursor = i + 1; //下一个元素指针+1
            /**
             * 因为下一个元素指针+1后,i就变成上一个元素了,所以先给上一个元素(lastRet)
             * 赋值为i,然后返回第i个元素的值,即当前元素的值
             */
            return (E) elementData[lastRet = i];
        }

        public void remove() {
            //迭代器是根据上一个元素来删除的,先判断有没有上一个元素
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification(); //同时修改检查函数,最下方详解

            try {
                ArrayList.this.remove(lastRet); //调用外部类中的删除方法,下方详解
                /**
                 * 删除成功后删除元素后面的元素会整体前移一个位置所以下一个指针需要-1
                 * 这里直接把删除元素的指针赋值给了下一个元素效果相当于-1了
                 */
                cursor = lastRet; 
                /**
                 * 由于没删除一个元素,上一个元素指针都会回归到-1,所以该remove方法要配合
                 * next方法来用,使得每次调用该方法lastRet都>0
                 */
                lastRet = -1;
                /**
                 * 由于ArrayList.this.remove(lastRet)该方法中修改了modCount的值,所以
                 * 这里也要将expectedModCount的值与modCount同步
                 */
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }

        //外部类中的删除方法,即ArrayList类中的删除方法
        public E remove(int index) {
            rangeCheck(index); //检查传进来的指数的范围
            
            modCount++; //修改次数+1
            E oldValue = elementData(index); //将要删除的元素取出以备方法返回时使用
            /**
             * 删除原理是从删除元素的以后的所有元素(不包括删除元素)整体前移一个位置,
             * 然后再把最后一个元素删除。下面numMoved计算的是删除元素后面的所有元素的
             * 长度,使用System.arraycopy方法去前移,功能是从(第一个参数的)数组的第
             * (index+1)位置开始复制(numMoved)个元素,然后放到(第二个参数的)数组
             * (index)的位置
             */
            int numMoved = size - index - 1;
            if (numMoved > 0)
                System.arraycopy(elementData, index+1, elementData, index,numMoved);
            //由于删除了所以size先-1,这时size位置的元素就是整体前移后结尾多出来的元素
            elementData[--size] = null; // clear to let GC do its work
    
            return oldValue;
        }

        //同时修改检查函数
        final void checkForComodification() {
            //通过检查两个修改计数器是否一致从而确定在迭代期间元素数组有没有被修改
            if (modCount != expectedModCount)
                //如果被修改则抛出同时修改异常
                throw new ConcurrentModificationException();
        }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值