ArrayList::iterator 中的 i >= elementData.length 是多余的吗?

is i >= elementData.length in ArrayList::iterator redundant?

这是ArrayList::Itr

的下一个方法
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];
}

它包含一个 if 语句:

if (i >= elementData.length)
    throw new ConcurrentModificationException();

我认为 i >= elementData.length 这种情况很少发生,除非用户调用 trimToSize 方法。而且我认为 if 语句是多余的,因为 checkForComodification 可以处理所有事情。 我说得对吗?

假设您的意思是 "redundant" 而不是 "abundant",那么不,它不是。

window调用checkForComodification()之后有一个小的(微小的)数组的大小可以改变,因为另一个线程已经调整了数组的大小ArrayList。发生这种情况的可能性非常小,但如果不存在此检查,next() 调用可能会抛出 ArrayIndexOutOfRangeException.


不利的一面是 next() 代码不能保证检测到所有并发修改。如果某个其他线程在 checkForComodification() 调用之后设法将一个元素添加到列表中,则该修改将不会被检测到。

不,不是。如果使用另一个线程,使得 ArrayListtrimTosize 被使用 after the

checkForComodification();

...但是 之前

Object[] elementData = ArrayList.this.elementData;

ArrayList.this.elementData 可能在此期间已更改(收到新的数组引用)。因此,在 将ArrayList.this.elementData 抓取到局部变量(elementData) 之后,检查数组 中的索引是否有效是正确且必要的。代码完成后,它有一个指向它将查找的数组的本地引用 (elementData) 和一个索引 i) 的本地变量。如果在代码获取之前对 ArrayList.this.elementData 的更改使索引无效,则此时代码是必要的,以便抛出正确的异常 (ConcurrentModificationException) 而不是 ArrayIndexOutOfBounds

例如,注意 ** 行:

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

另一个线程可以进来。只有当我们对我们将要使用的数组有自己的引用时(一旦最后 ** 行完成)我们知道引用不会改变(因为它是本地的)。