【问题标题】:How does next() method on iterators work?迭代器上的 next() 方法如何工作?
【发布时间】:2018-05-20 19:12:01
【问题描述】:

我对迭代器上的 next() 方法有疑问。如果我的代码中有这行(arrayOfStrings size = 4):

Iterator<String> it = arrayOfStrings.iterator(); //arrayOfString is ArrayList<String>

while(it.hasNext()) {
    String e = it.next();
    System.out.println(e);
}

在第一次迭代时,迭代器开始指向索引为 0 的元素?还是像“索引-1”?

我问是因为据我所知next() 方法返回集合中的下一个元素。

那么,如果在第一次迭代中,当调用 next() 时,迭代器从索引 0 开始,它会返回索引 1 处的元素,而我将无法对索引 0 处的元素执行任何操作?

【问题讨论】:

  • 您显示的代码应正确打印ArrayList所有元素it.next() 调用将在第一次调用时返回第一个元素。该元素通常用 index 0 表示。
  • 你知道你可以查看java类的源代码来了解它们的作用和方法吗?
  • 当您输入文本时,将迭代器视为光标,假设您在某个文本文件中有“abc”,并且您想读取这些字母中的每一个,在最开始的光标将就在字母“a”之前,当你调用 next 时,想象它向右移动一个位置并选择它移动过的元素,所以你现在可以打印该元素或用它做一些事情,然后在下一次调用时它会移动过去跨过“b”,这样你就可以用“b”做点什么,它会一直这样做,直到它没有东西可以移动。
  • 这都是关于文档的,因为它只是说“返回下一个元素”。从技术上讲,next 意味着之前已经存在。所以在我看来,问第一个元素是什么是合理的。文档可以更好地解释这一点。

标签: java iterator


【解决方案1】:

next 视为一个两步过程。首先它获取迭代器中的下一项,然后递增指针以指向下一项。因此,当您创建一个新的迭代器时,它会被初始化为返回列表中的第一项(索引 0)。

【讨论】:

    【解决方案2】:

    我想象迭代器工作方式的方式是将其视为放置在 索引之间的东西。因此,当第一个 next() 被调用时,您可以返回存储在 [0] 索引下的值,并且在该调用之后,迭代器在索引 [0] 和 [1] 之间等待下一次调用为您返回存储在索引中的值[1]。在第二个 next() 调用之后,迭代器在 [1] 和 [2] 之间等待......

    这只是我习惯迭代器的方式,但它可能对你有所帮助。

    【讨论】:

      【解决方案3】:

      您显示的代码将正确打印ArrayList所有元素it.next() 调用将在第一次调用时,也是第一个元素。这个元素通常用 index 0 表示。

      请注意,您可能想要重命名arrayOfStrings,因为从技术上讲,它不是数组,它更像是List。用户可能会由于名称认为它是一个数组。


      文档

      在我看来你是对的,documentation of the method 可能有点令人困惑,因为它非常紧凑:

      返回迭代中的下一个元素。

      但是描述可能需要如此不详细,因为Iterator 是一个非常常用的接口,不仅用于集合。我可以想象一个类,其中 第一个迭代元素 不应该是底层结构的第一个元素。例如,在给定点之前已经读取的某种流。所以基本上由实现类来决定第一个元素是什么。但对于集合来说,它确实是第一个元素(索引 0)。


      对于每个

      还请注意,您显示的迭代等同于 扩展 for-loop (for-each) 在 Java 中的工作方式。所以像

      这样的语法
      for (Item item : items) {
          ...
      }
      

      将被视为

      Iterator<Item> iter = items.iterator();
      while(iter.hasNext()) {
          Item item = iter.next();
          ...
      }
      

      事实上,这就是为什么您可以在扩展的for循环中使用所有实现Iterable的东西的原因。

      知道这一点,如果iter.next() 会跳过第一个元素,那会很混乱。我的意思是 for-each 这个名字应该迭代 所有 元素。


      见解

      让我们仔细看看该方法是如何实现的。因此,我们将首先看看ArrayList#iterator 做了什么。看看它的source code

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

      Itr 类是 ArrayList (source code) 的私有类。而hereItr#next 方法:

      @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];
      }
      

      所以它本质上返回的是索引i 处的元素,这是光标在调用方法时所在的位置。它也已经为下一次调用该方法将光标前进了一个。

      但是,光标被隐式初始化为0,原因是:

      int cursor; // Default value for int is 0
      

      所以next 的第一次调用确实会返回索引0 处的元素,即第一个元素

      【讨论】:

      • 感谢您非常详细的回答。但是我从您在此处提供的Itr#nextmethod 代码中看不到光标和大小参数的来源?这些参数在这里是如何传递的?
      • 迭代器来自arraylist,它在内部将当前索引作为字段记住。
      猜你喜欢
      • 1970-01-01
      • 2012-06-19
      • 1970-01-01
      • 1970-01-01
      • 2014-01-20
      • 1970-01-01
      • 1970-01-01
      • 2018-01-17
      相关资源
      最近更新 更多