当Iterator.next()方法与java.util.Queue一起使用时,在for语句中执行什么操作?

zbwhf8kr  于 2023-05-12  发布在  Java
关注(0)|答案(2)|浏览(138)

例如:

public class Test {

    public static void main(String[] args) {
        Queue<String> names = new LinkedList<>(Arrays.asList("First", "Middle", "Last"));
        System.out.println("Queue before the loop: " + names);

        System.out.println("Printing loop...");
        for (Iterator<String> i = names.iterator(); i.hasNext();) {
            String name = i.next();
            System.out.println(name);
        }

        System.out.println("Queue after the loop: " + names);
    }
}

输出:

Queue before the loop: [First, Middle, Last]
Printing loop...
First
Middle
Last
Queue after the loop: [First, Middle, Last]

我知道next()方法如何遍历 LinkedList。但是当它在 * Queue.iterator()* 上被调用时,比如i.next(),它会做什么?
从输出中可以看到,它没有从队列中删除任何元素。

  • 我认为应该是这样,因为队列只有remove()/poll()。*
iyr7buue

iyr7buue1#

Iterator只是用来遍历一个Collection。在这种情况下,您可以使用for-each来获得相同的结果:

for(String name : names){
  System.out.println(name);
}

然而,根据你的问题,我假设你想迭代Queue,***弹出***并以FIFO顺序打印每个项目(因此使用你的LinkedList)。在这种情况下,您可能只需要循环names.size()次,并调用.remove()在每次迭代中弹出一个项,如下所示:

for(int n = names.size(); n > 0; n--){
  String name = names.remove();
  System.out.println(name);
}

输出:

Queue before the loop: [First, Middle, Last]
Printing loop...
First
Middle
Last
Queue after the loop: []

在线试用

编辑:为了解释更多关于.iterator()的内容:
如果我们看the source code of the Iterator,我们可以看到它是一个接口。每个集合实现都有自己的Iterator实现。
查看the source code of the Queueiterator()方法如下:

/**
 * Returns an iterator that iterates over the items in this queue in FIFO order.
 *
 * @return an iterator that iterates over the items in this queue in FIFO order
 */
public Iterator<Item> iterator() {
    return new ListIterator();
}

// an iterator, doesn't implement remove() since it's optional
private class ListIterator implements Iterator<Item> {
    private Node current = first;  // node containing current item

    public boolean hasNext() {
        return current != null;
    }

    public void remove() {
        throw new UnsupportedOperationException();
    }

    public Item next() {
        if (!hasNext()) throw new NoSuchElementException();
        Item item = current.item;
        current = current.next;
        return item;
    }
}

正如您所看到的,当在iterator()方法中创建ListIterator时,它将Queue的Node first存储为其current
在实际的next()-方法中,它既不使用Queue的remove()方法,也不使用poll()方法(也不使用get()..),因此实际上并没有弹出这些项。相反,它只是用Item item = current.item临时存储当前Node;然后将current节点更新到下一个current = current.next节点;之后它将返回临时item

1aaf6o9v

1aaf6o9v2#

由于names是一个 LinkedList 对象,并且 LinkedList 中没有任何iterator()方法,因此names.iterator()将在 AbstractSequentialListLinkedList 的直接超类)中调用该方法。
然而,通过跟踪调用堆栈 (可以通过任何像样的java IDE的GUI调试器轻松完成),当初始化i = names.iterator()时,可以很容易地看到它在这里调用了listIterator(0)方法。即使 AbstractList 有自己的listIterator(int index)实现,LinkedList 也覆盖了相同的方法;

  • LinkedList.java* 的片段:
package java.util;

public class LinkedList<E>
    extends AbstractSequentialList<E>
    implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{   
    public ListIterator<E> listIterator(int index) {
            checkPositionIndex(index);
            return new ListItr(index);
    }
    private class ListItr implements ListIterator<E> {
        private Node<E> lastReturned = null;
        private Node<E> next;
        private int nextIndex;
        private int expectedModCount = modCount;
        ListItr(int index) {
            // assert isPositionIndex(index);
            next = (index == size) ? null : node(index);
            nextIndex = index;
        }
        public boolean hasNext() {
            return nextIndex < size;
        }
        public E next() {
            checkForComodification();
            if (!hasNext())
                throw new NoSuchElementException();
            lastReturned = next;
            next = next.next;
            nextIndex++;
            return lastReturned.item;
        }
    *
    *   (code contraction...)
    *
        final void checkForComodification() {
                if (modCount != expectedModCount)
                    throw new ConcurrentModificationException();
            }
    }
}

因此,显然names.iterator()将通过return new ListItr(index)返回一个对象,return new ListItr(index)LinkedList 的内部类。
现在我们可以清楚地看到,在调用i.next()时,它实际上调用了内部类***ListItr***中的next()方法。它还使用类变量;

private Node<E> next;

跟踪迭代器接下来要指向的地方。
这在考虑增强的for循环的性能时起作用。

  • enhance-for-loop*s的Oracle文档段:
for (I #i = Expression.iterator(); #i.hasNext(); ) {
    VariableModifiersopt TargetType Identifier = (TargetType) #i.next();
    Statement
}

正如您所看到的,这使用了#i.next()方法,由于names(在原始问题的示例中)是一个类型为*Queue*的变量,可以在黑暗中假设增强for循环中的#i.next()使用了 AbstractList 中的此实现,并且它可疑地使用了一些get(int index)方法,因此性能较差(一个像我一样可怜的不幸的人,做了同样的推导,陷入了一堆代码中。LOL)。
关于那个错误的推论,我在这个论坛上问了这个问题,经过几天的深入挖掘,现在我可以看到,当
使用增强的for循环迭代 LinkedList 对象
时,没有任何性能降低(据我所知没有),因为事实是,

  • iterator object*(#i)使用变量Node<E> next来保持对下一个对象的引用,以便在 enhanced-for-loop 的下一次迭代中使用。

相关问题