6

同様の質問がありますが、私が聞きたいこととは異なります。Iterator が変更をチェックする方法を知りたいです。

このリンクは、その実装が AbstractList クラスに存在し、リストサイズが変更された回数を提供する int 変数 modCount が定義されていることを示しています。この値は、すべての next() 呼び出しで使用され、関数 checkForComodification() の変更をチェックします。

しかし、私はそれを本当に理解できませんでした。次のすべての呼び出しの後にのみ値がチェックされる場合、同じ呼び出しで削除に続いて追加を行うと、サイズは変更されず、modCount も変更されません。ただし、同じループ反復で削除および追加すると、例外もスローされます。

4

2 に答える 2

8

Collection実装のコードを見ると、選択できますArrayListmodCountで宣言された変数がありAbstractListます。

protected transient int modCount = 0;

そして、すべての変更方法 (たとえばremove) でArrayList

public E remove(int index) {
    rangeCheck(index);

    modCount++;
    //....

したがって、はインクリメントmodCountされるだけです。減少することはありません。

では、次のIteratorようになります。

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

作成時に撮影しexpectedModCountたスナップショットはどこにありますか。modCountIterator

そのため、 の同じインスタンスが使用されている間に基になるものが変更された場合、がスローされます。ListIteratorConcurrentModificationException

十分な変更を行った場合、intオーバーフローして再び元の値に戻るというまれなケースがあると思いますが、これはかなり大きな数または変更になります。正確には2 32です。

于 2013-10-08T20:38:55.250 に答える
6

modCountリストが変更されると常に増加するため (したがってmod数)、削除があった場合にも増加するはずです。したがって、削除と追加の呼び出しの両方で増加します。

ボリス・ザ・スパイダーがオーバーフローするコーナーケースがあると言ったようにmodCount、次のようにして確認できます。

List<Integer> nums = new ArrayList<>();
for(int i = 0; i < 10; i++) nums.add(i);
for(int n : nums) {
    System.out.println(n);
    for(int i = -1; i < Integer.MAX_VALUE; i++) {
        nums.add(i);
        nums.remove(nums.size() - 1);
    }
}

例外をスローせずに(ゆっくりと)0から9を出力します。

于 2013-10-08T20:33:47.467 に答える