【问题标题】:Usage of Iteration's .hasNext(); and .next(); methods in Java使用迭代的 .hasNext();和 .next(); Java中的方法
【发布时间】:2020-12-30 00:39:09
【问题描述】:

两天来,我对迭代接口的 .hasNext();next(); 方法感到非常困惑,尤其是在 while 循环中。举个例子吧:

import java.util.*;  // imported whole java.util package.

class Main {
  public static void main(String[] args) {
    ArrayList<String> cars = new ArrayList<String>();  // created ArrayList which name is cars.
    cars.add("Volvo");
    cars.add("Mercedes"); 
    cars.add("BMW");


    Iterator<String> x = cars.iterator();

    while(x.hasNext()) {
      System.out.print(x.next() + " ");  // It prints Volvo Mercedes BMW
    }
  }
}

我知道 .hasNext(); 是布尔值,如果迭代有元素,它会返回 true。 .next(); 方法返回下一个元素。在第一个元素沃尔沃之后,它返回 while(x.hasNext()) 并再次进入循环内部,但是这个循环的计数器在哪里?我的意思是在打印沃尔沃之后,它如何进入下一个元素?它返回所有元素,如果没有更多 .hasNext(); 返回 false 并且代码继续下一行是简单的答案和正确的但我想清楚地理解它。

【问题讨论】:

  • 这能回答你的问题吗? How a java iterator works internally?
  • 没有 @Turamarth ,我在问 while 循环在这个迭代中是如何工作的。因为没有计数器,但它的行为就像有一个计数器并返回下一个值。你分享的问题是关于迭代的,而不是我的问题。
  • 迭代器实现本身是有状态的,并存储某种引用或计数器。每次调用next() 都会增加该计数器。当然,确切的方法是特定于实现的。
  • @ArvindKumarAvinash 感谢您提供信息,但我仍然尝试理解回复。我在问问题并得到答案。在我理解清楚之后,我绝对会检查正确和最容易理解的答案。

标签: java arraylist while-loop iteration


【解决方案1】:

实际上 iterator() 方法为您的(比方说)Arraylist 中的所有元素创建一个迭代器。现在在您的代码中,while 循环 x.hasNext() 的条件 检查列表是否包含元素,如果是则返回 true,否则返回 false。

现在 x.next() 指向您的 ArrayList 中的第一个元素(例如 LinkedLists)并存储该对象(在您的情况下为沃尔沃)。当您调用此方法时,它基本上为您提供 List 中该对象的引用,并且 Iterator 移动到 List 中的下一个元素。调用 next() 方法时,迭代器(在您的情况下为 x)返回对象,然后移动到下一个元素(在您的情况下为梅赛德斯)。

现在,当您再次调用 next() 方法时,您会发现 Mercedes 已返回。要知道它是如何工作的,输入 System.out.println(x.next()) 三次而不是 while 循环你会明白它会移动到下一个位置。如果您第四次键入 System.out.println(x.next()) 它将给出异常,因为您的列表中没有更多元素。 线程 "main" java.util.NoSuchElementException 中的异常 这是异常。

这就是为什么使用 hasNext() 方法来检查元素是否存在的原因。 您可以将此与打印链接列表(如果您知道的话,数据结构)进行比较,我们将一个对象指向头节点打印它并移动到下一个节点。 Same Case 在这里它返回当前元素(对象)并移动到下一个元素(对象)。

【讨论】:

  • 很好的解释,但准确地说next() 不会复制对象。它只返回对列表内对象的引用。
  • 谢谢 Abhishek 我了解next(); 打印当前对象并存储它,然后移动下一个但不打印它。在此之后,循环返回while(x.hasNext()) 步骤并检查是否有任何元素?我的困惑完全在这里,当循环回到while 括号内部时,它不会重新启动诸如next(); 方法之类的所有内容吗?当它回到next(); 方法时,程序如何知道next(); 已经打印了第一个元素? while work 机制没有问题吗?
  • 思考下一个();就像方法 nextInt();从控制台提供价值。同样在这里 next() 只是为您提供迭代器指向的参考。不要认为 next() 是一个对象,Iterator 类中会有一个对象,它跟踪 Iterator 类中的元素,而 next() 将 返回引用并指向 next() 。所以基本上 x.next() 将 用下一个值更新该 reference_variable 并返回旧值,而不是跟踪该元素本身。当您创建对象 Iterator x 时,跟踪对象在 Iterator 类中完成。
【解决方案2】:

while 是 java-ese 用于:继续这样做,直到事情发生变化。

有点像这个常见的家务活:

如何洗碗

  • 检查柜台右侧是否还有脏盘子。
  • 如果有,请执行洗碗操作:拿起最近的脏盘子并清洗,然后将其存放在柜台左侧,然后返回此算法的开头。
  • 否则(没有脏盘子),你就完了。
while (counterRightSide.hasItems()) {
    Dish dirty = counterRightSide.fetch();
    Dish clean = sink.clean(dirty);
    counterLeftSide.stow(clean);
}

编辑:我现在意识到“厨房柜台”是一个不幸的例子,因为同音词“厨房柜台”和“代码中的柜台”。我将使用“累加器”而不是“代码中的计数器”来解决这种混淆。

请注意这里也没有蓄能器,洗盘子时也没有在脑子里数数。你可以先盘点你有多少脏盘子(比如 15 个盘子),然后写一个协议,在你完成这项工作之前,你抓取一个脏盘子正好 15 次,但你肯定意识到那是只有一种方法,另一种方法是……每次洗完一个脏盘子后,检查是否还有脏盘子。上面的代码是这样工作的。

请注意,从厨房柜台右侧“获取”物品的操作会更改该厨房柜台的属性。它现在少了一件。

这同样适用于迭代器:在迭代器上调用 .next() 会以某种形式改变它。毕竟,如果你调用 next 两次,这些调用的结果是不同的。与连续多次调用someArrayList.get(5) 相比;这根本不会改变arraylist,因此你每次都会得到同样的东西。 next() 不是这样的。

那么它是如何工作的呢?谁来计算这些东西?

嗯,这就是抽象的妙处! “集合”是可以做一些事情的东西,例如“它必须能够报告它拥有多少物品”,以及“它必须能够为你装饰一个可以用来循环遍历的对象”它拥有的每个项目”。

这就是迭代器:一个可以做到这一点的对象。

那么它是如何工作的呢? 谁知道!没关系!只要你能做到这些,你就可以成为一个集合,你可以随心所欲地执行任务。

好的,但是像 ArrayList 这样的普通集合是如何做到这一点的呢?

当然是计数器。这是实现:

    public Iterator<T> iterator() {
        return new Iterator<T>() {
            int counter = 0; // here it is!
 
            public boolean hasNext() {
                return counter < size();
            }

            public int next() {
                return get(counter++);
            }
        };
    }

您正在获取此对象并在您的代码中引用它(您的x 变量),并且该对象有一个带有计数器的字段。你看不到它;它是私有的,实际上不在 Iterator 类型中(Iterator 是一个接口;你得到的是它的一些未知子类型,并且包含计数器变量)。假设您通过在数组列表上调用 .iterator() 来获取迭代器。如果您在其他东西上调用它,则可能有也可能没有计数器 - 只要迭代器有效,它如何工作并不重要,这就是接口的美妙之处。

【讨论】:

    【解决方案3】:

    while 循环检查条件,当条件为真时,执行循环体并自行迭代,

    while(condition){
    //do something.
    }
    

    hasNext() 是来自 Iterator 接口的方法,如果“迭代”有更多元素,则返回 true,如果没有更多元素,则返回 fals,并且不再进入 while 循环体:

    while(x.hasNext){
    //do something.
    }
    

    next() 方法是来自 Iterator 接口的方法,它返回迭代的下一个元素。

    while(x.hasNext){
    x.next();
    }
    

    【讨论】:

    • 长话短说,hasNext(); 检查所有数组(对于我的情况),如果有一个元素尚未检查(或打印或我能在这里说什么?)它返回 true,然后next(); 获取之前没有打印的元素?如果我错了,请纠正我。
    【解决方案4】:

    我的意思是在打印沃尔沃之后,它如何进入下一个元素?它 返回所有元素,如果没有更多 .hasNext();返回假 并且代码继续到下一行是简单的答案和正确的,但我 想看清楚。

    int cursor;       // index of next element to return
    //...
    
    public boolean hasNext() {
        return cursor != size;
    }
    
    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];
    }
    //...
    

    以上是ArrayList#hasNextArrayList#next 的实现方式。代码直截了当,易于理解。您可以使用反编译器或here查看完整代码。

    【讨论】:

      猜你喜欢
      • 2020-12-15
      • 1970-01-01
      • 2013-03-29
      • 1970-01-01
      • 2023-03-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-25
      相关资源
      最近更新 更多