有位小朋友最近正在为年后换工作做准备,但是遇到一个问题,觉得很不可思议的一道笔试题。然后我把这道题发到技术群里,发现很多人居然不知道,很多都是连蒙带猜的说。感觉很有必要写一篇文章来说道说道。 阅读下面这段代码,请写出这段代码的输出内容: 他写出来的答案是: 奇怪的是,你把这道题目发给你身边人,让他们回答这道面试题输出结果是什么,说这个结果的人非常多。不行你试试奇怪的笔试题
import java.util.ArrayList;
import java.util.Iterator;
import java.util.*;
public class Test {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("1");
list.add("2");
list.add("3");
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
String str = (String) iterator.next();
if (str.equals("2")) {
iterator.remove();
}
}
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
System.out.println("4");
}
}1
3
4
答案明显不对,因为在第一个while里的 iterator.hasNext()==false后才会到第二个while里来,同一个Iterator对象,前面调一次iterator.hasNext()==false,再判断一次结果不还是一样吗?,
所以第二个while判断为false,也就不会再去遍历iterator了,由此可知本体答案是:4。
下面我们来分析一下为什么是具体底层是怎么实现的。
public interface Iterator<E> {
//每次next之前,先调用此方法探测是否迭代到终点
boolean hasNext();
//返回当前迭代元素 ,同时,迭代游标后移
E next();
/*删除最近一次已近迭代出出去的那个元素。
只有当next执行完后,才能调用remove函数。
比如你要删除第一个元素,不能直接调用 remove() 而要先next一下( );
在没有先调用next 就调用remove方法是会抛出异常的。
这个和MySQL中的ResultSet很类似
*/
default void remove() {
throw new UnsupportedOperationException("remove");
}
default void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (hasNext())
action.accept(next());
}
}
这里的实现类是ArrayList的内部类Itr。
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
//modCountshi ArrayList中的属性,当添加或删除的时候moCount值会增加或者减少
//这里主要是给fail-fast使用,避免一遍在遍历,一遍正在修改导致数据出错
//此列表在结构上被修改的次数。结构修改是指改变结构尺寸的修改列表,
//或者以这样的方式对其进行扰动,进步可能会产生错误的结果。
int expectedModCount = modCount;
public boolean hasNext() {
//cursor初始值为0,没掉一次next方法就+1
//size是ArrayList的大小
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
//把ArrayList中的数组赋给elementData
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
//每调用一次next方法,游标就加1
//cursor=lastRet+1
cursor = i + 1;
//返回ArrayList中的元素
return (E) elementData[lastRet = i];
}
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
//调用ArrayList中remove方法,溢出该元素
ArrayList.this.remove(lastRet);
//cursor=lastRet+1,
//所以此时相当于cursor=cursor-1
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
再回到上面题目中:
第1次循环
hasNext方法中:cursor==0, size==3,所以cursor != size返回true。
next方法中:cursor=0+1。返回"1"。
第2次循环
hasNext方法中:cursor==1, size==3,所以cursor != size返回true。
next方法中:cursor=1+1。返回"2"。
remove方法中:cursor==cursor-1==2-1=1,把ArrayList中的"2"给删除了,所以size==2。
第3次循环
hasNext方法中:cursor==1, size==2,那么cursor != size返回true。
next方法中:cursor=1+1==2;返回"3"。
第4次循环
hasNext方法中:cursor==2, size==2,所以cursor != size返回false。
所以,最后只输出"4",即答案为4.
参考:ii081.cn/2Jc3e
最近有粉丝想要一些电子书,这次直接分享我收藏的200本技术类电子书,打包发给大家,如有需要,关注公众号领取哟~
点赞越多,bug越少
联系客服