【问题标题】:What is internal implementation of Iteration in java that allows remove() method to work?java中允许remove()方法工作的迭代的内部实现是什么?
【发布时间】:2019-01-05 07:19:24
【问题描述】:

通过 foreach 循环迭代时,列表中的任何项目都无法删除。但是,当我们通过迭代器对其进行迭代时,可以通过迭代器的 remove() 方法将其移除。

我了解快速故障和故障安全的概念,并且还知道 Iterator 是 java 为我们提供删除选项的方式。但是想知道java提供的Iterator的remove()方法的内部实现,方便这个操作。

import java.util.*;
public class RemoveCollection {
public static void main(String[] args) {
    List<String> ls = new ArrayList<String>();
    ls.add("apple");
    ls.add("orange");
    ls.add("kiwi");

    Iterator it = ls.iterator();
    while(it.hasNext()) {
        it.next();
        //works fine and the item is removed from list
        it.remove();
    }

    ls.add("apple");
    ls.add("orange");
    ls.add("kiwi");
    while(it.hasNext()) {
        it.next();
        //throws concurrentmodification exception
        ls.remove();
    }
  }
}

【问题讨论】:

  • 提示:通常在安装JDK时,您可以选择安装Java类的源代码:在JDK的lib文件夹中的src.zip

标签: java list collections iterator


【解决方案1】:

看JDK自带的ArrayList源码就知道了:

ArrayList 有这个字段(继承自 AbstractList):

protected transient int modCount = 0;

每次对列表执行操作时,它都会递增。例如,ArrayList.remove() 有以下指令:

modCount++;

ArrayList的迭代器代码如下:

int expectedModCount = modCount;

public E next() {
   checkForComodification();
   [...]
}

final void checkForComodification() {
    if (modCount != expectedModCount)
        throw new ConcurrentModificationException();
}

因此,如您所见,当它迭代时,它会检查列表的 modCount 是否未被修改。

它的remove() 方法执行以下操作:

ArrayList.this.remove(lastRet);
[...];
expectedModCount = modCount;

所以它从列表中删除元素,然后更新它的expectedModCount,这样在调用checkForComodification()时,用迭代器完成的下一个操作不会失败。

要理解的关键是iterator() 方法返回一个可以访问列表内部结构的对象。不仅能够迭代其元素,还能够检查该列表是否在使用迭代器完成的两个操作之间被修改。

【讨论】:

  • 抱歉,我想知道 Iterator 的 remove() 方法,而不是 ArrayList。我的意思是,我们通过说 Iterator itr = ls.iterator() 获得一个 Iterator 引用,然后使用 itr.remove()。所以这基本上是被调用的 ArrayList 的方法?我不知道。让我看看。谢谢
  • 我的回答解释了这一点。但是你需要完整阅读它:ArrayList 的迭代器有以下代码:[...] 并且它的 remove() 方法执行以下操作:[...]
  • 还想知道为什么根据 oracle java 的官方文档迭代器快速失败。它在不抛出 ConcurrentModificationException 的情况下安全地删除列表中的项目,但它仍然快速失败
  • 它很快就失败了,因为只要你调用 next(),它就会在迭代时检测列表是否被修改。这就是 checkForComodification 方法的作用。
【解决方案2】:

List&lt;E&gt; 扩展了 AbstractList&lt;E&gt;。这个抽象类包含方法iterator(),它返回一个新的迭代器(第287行)。你可以看到source code

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

下面几行(第 330 行)有一个 private class Itr implements Iterator&lt;E&gt; 的定义,它在第 368 行定义并实现了方法 remove()

public void remove() {
    if (lastRet < 0)
        throw new IllegalStateException();
    checkForComodification();

    try {
        AbstractList.this.remove(lastRet);
        if (lastRet < cursor)
            cursor--;
        lastRet = -1;
        expectedModCount = modCount;
    } catch (IndexOutOfBoundsException e) {
        throw new ConcurrentModificationException();
    }
}

【讨论】:

  • 谢谢。会回来,去看看
猜你喜欢
  • 2018-04-05
  • 2020-01-09
  • 1970-01-01
  • 2013-10-21
  • 2015-03-20
  • 1970-01-01
  • 2014-05-23
  • 2017-03-03
  • 2012-06-19
相关资源
最近更新 更多