一、关于remove
- 如果是remove(int index) 会先调用
private void rangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
这里有我们熟悉的IndexOutOfBoundsException数组越界异常;
- 如果是remove(Object o) 会转化成数组下标调用
private void fastRemove(int index) {
modCount++;
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,numMoved);
elementData[--size] = null; // clear to let GC do its work
}
最终调用System.arraycopy,以移动后续数据覆盖之前数据的方式实现删除。
二、关于保存数据的实体
transient Object[] elementData;
之所以定义成transient是因为,elementData默认初始化长度是10(DEFAULT_CAPACITY),当实际长度不足容量时,比如2,则后8个没存实际数据的位置是不会被序列化的。
三、关于forEach遍历时
- 实际上for( : ) 是先会调用内部类Itr的hasNext判断是否有下个元素,
之后调用next()取值给for中的变量。 - 这里要注意,在next时会调用
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
其中modCount每次对数组操作都会++,记录操作次数。
而在迭代器遍历的过程中,一旦发现这个对象的mcount和迭代器中存储的mcount不一样那就抛异常。
这就是为什么我们循环遍历中第二次调用remove等操作会异常的原因。
Fail-Fast 机制在ArrayList,LinkedList,HashMap中都会看到。
- modCount是定义在父类AbstractList.java中
protected transient int modCount = 0;
而expectenModCount定义在私有内部类(迭代器的实现)Itr中
int expectedModCount = modCount;