迭代器中hasNext()与next()的指针问题

前言

最近找工作,遇到很多底层的问题,于是决定把Java中常用的类、方法等的底层好好看看,再学学。在学到迭代器时,在hasNext()与next()的初始指针的指向问题上出现了分歧,有说起始指针为0的,也有说为-1的。然后去看了源码,自认为是懂了一点,于是记录一下,如果有错误、不严谨的地方,望路过的大佬能批评指正。

理解过程

首先,创建一个list,然后获取迭代器对象,完成他的迭代器遍历的流程

// 1、创建集合并添加元素
Collection<String> coll = new ArrayList();
coll.add("aaa");
coll.add("bbb");
coll.add("ccc");
// 2、获取迭代器对象
Iterator<String> it = coll.iterator();
// 3、利用循环不断去获取集合中的每个元素
while(it.hasNext()){
    // 获取元素并移动指针
    String str = it.next();
    System.out.println(str);
}

在这个过程中,coll.iterator()在底层实际是返回了一个Itr对象,也就是说我们使用的迭代器的方法都是来自于这个Itr类的

public Iterator<E> iterator() {
    return new Itr();
}

下面就是Itr类部分方法,在hasNext()与next()两个方法中,我们只需要关注前两个成员变量(cursor和lastRet),第三个变量是关于迭代器遍历中增删限制的,这里不做讨论。

cursor,英文翻译就是指针、游标、光标;源码注释为下一个返回元素的索引;初始化为0。lastRet,根据源码注释,解释为返回的最后一个元素的索引,如果没有就为-1;初始化为-1。

先看hasNext()方法,只做了cursor与size的比较,并没有做指针的移动等操作。                         

然后是next(),checkForComodification()是与第三个参数有关,目前不管他。

先把目前的游标用一个局部变量 i 存储,然后比较 i 是否越界(集合长度),再把底层数组用局部变量的数组存储(可以提高效率),然后比较 i 是否越界(数组长度),再然后移动游标(i+1,本质上也就是cursor+1),最后利用 lastRet 去取数组中的元素。注意,此时的 lastRet 是比 cursor 少1的。

private class Itr implements Iterator<E> {
    int cursor;       // index of next element to return --> 下一个返回元素的索引
    int lastRet = -1; // index of last element returned; -1 if no such --> 返回最后一个元素的索引;如果没有-1
    int expectedModCount = modCount;

    Itr() {}

    public boolean hasNext() {
        return cursor != size;
    }

    @SuppressWarnings("unchecked")
    public E next() {
        checkForComodification();
        int i = cursor;
        if (i >= size)
            throw new NoSuchElementException();
        Object[] elementData = ArrayList.this.elementData;
        if (i >= elementData.length)
            throw new ConcurrentModificationException();
        cursor = i + 1;
        return (E) elementData[lastRet = i];
    }
}

结论

1、 在初学hasNext()方法时,遇到的每个人(同学、老师...)对其的描述都是:查看他是否有下一个元素。这种描述就让我以为该方法是在查看下一个地址上是否有元素,然而源码中做的操作是,比较目前游标是否达到了集合的实际长度,也就是在比较游标是否越界。

2、next()中其实涉及了两个指针,cursor与lastRet。cursor起始为0,lastRet起始为-1。那哪一个才是指针的起始位呢?我们可以反复琢磨一下他的源码注释。cursor:下一个返回元素的索引;lastRet:返回的最后一个元素的索引。再结合elementData[lastRet = i]这句来看。实际就可以看成指针先移动到下一个位置,再取之前位置上的元素。所以我个人认为,起始位是0。

3、lastRet主要是用来记录遍历到的最新一个元素的位置的,而真正移动的指针是cursor,lastRet的值也是由 cursor 来的,所以起始位为0应该是最合理的解释。

  • 8
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
迭代器的`hasNext()`方法用于检查迭代器是否还有下一个元素可以迭代。它返回一个布尔值,如果还有下一个元素,则返回`true`,否则返回`false`。\[1\] 在示例代码,通过`Iterator`接口的实现类的对象`itr`调用`hasNext()`方法来检查集合是否还有下一个元素可以迭代。如果返回`true`,则执行相应的操作,如果返回`false`,则退出迭代循环。\[3\] 在迭代过程,每次调用`next()`方法后,迭代器会自动将指针移动到下一个元素,同时`hasNext()`方法会更新迭代器的状态,以便下一次调用时能正确判断是否还有下一个元素可以迭代。\[1\] 总结来说,`hasNext()`方法是用来检查迭代器是否还有下一个元素可以迭代的方法,它在迭代过程起到了判断条件的作用。\[1\]\[3\] #### 引用[.reference_title] - *1* *2* [了解迭代器(hasNext(),next()和 其的强制类型转换)](https://blog.csdn.net/Ameir_yang/article/details/80845489)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [迭代器的部分解释](https://blog.csdn.net/m0_64773063/article/details/124482911)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值