之前的文章中对java中的Fast-Fail机制进行过简单的介绍,笔者在后来的学习中发现了这个机制的一点漏洞,特此补充下,
如有不解,可看上篇文章
失败机制的漏洞
这个漏洞要分为2部分讲:
1)ArrayList
在ArrayList中删除倒数第二个元素时不会报错,ArrayList中定义了一个私有内部类来实现Iterator接口,并对hasNext()方法进行了重写,部分源代码如下:
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;
Itr() {}
public boolean hasNext() {
return cursor != size;
}
在这里有一个变量名为cursor,也就是游标,它总是指向当前索引的下一个索引,在删除倒数第二个索引时,在hasNext()方法中会进行判断,假设集合有5个元素,则就是判断4!=4,显然返回false,就不会进入循环调用下一个.next()方法,更不会进行expectedModCount = modCount的判断
public E next() {
checkForComodification();
if (!hasNext())
throw new NoSuchElementException();
lastReturned = next;
next = next.next;
nextIndex++;
return lastReturned.item;
}
在next()方法中会调用checkForComodification()方法进行检查
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
也就不会抛出异常
2)LinkedList
在LinkedList中删除倒数第一个或者倒数第二个元素时均不会报错,LinkedList中同样定义了一个私有内部类,但其实现的接口为ListIterator,对hasNext()方法进行了重写,部分源代码如下:
private class ListItr implements ListIterator<E> {
private Node<E> lastReturned;
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;
}
可见此时hasNext()的判断条件变为了nextIndex < size,这个时候同样假设集合中有5个元素,则在删除倒数第一个或第二个元素时的判断条件为4<4以及5<4,显然返回false,之后的就不用我多说了吧跟上面一样不会进入下一次循环从而不会进行检查更不会抛出异常 !
本文主要探讨Java中集合删除元素时失败机制的漏洞。以ArrayList和LinkedList为例,分析了在删除特定位置元素(ArrayList删除倒数第二个、LinkedList删除倒数第一或第二个)时不报错的原因,涉及到集合内部类对hasNext()方法的重写及相关判断逻辑。
2374





