有位小朋友最近正在为年后换工作做准备,但是遇到一个问题,觉得很不可思议的一道笔试题。然后我把这道题发到技术群里,发现很多人居然不知道,很多都是连蒙带猜的说。感觉很有必要写一篇文章来说道说道。
奇怪的笔试题阅读下面这段代码,请写出这段代码的输出内容:
- 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。
下面我们来分析一下为什么是具体底层是怎么实现的。
这里的Iterator是什么?
Iterator说明
- 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();
- }
- }
再回到上面题目中:
第一个iterator.hasNext()
第2次循环
第3次循环
第4次循环
第二个iterator.hasNext()
hasNext方法中:cursor==2, size==2,所以cursor != size返回false。
所以,最后只输出"4",即答案为4.
Iterator与泛型搭配
foreach和Iterator的关系
使用for循环还是迭代器Iterator对比
总结
本文转载自微信公众号「Java后端技术全栈」,可以通过以下二维码关注。转载本文请联系Java后端技术全栈公众号。
注册域名 怎么开通 邮箱 ?开通邮箱,需要先注册 域名 。开通 企业邮箱 ,不仅能...
1. 接口描述 接口请求域名: cvm.tencentcloudapi.com 。 本接口(SyncImages)...
近期,随着春节档电影《你好,李焕英》的热映以及片中出现的贾玲母亲年轻时旧照...
TOP云 (west.cn)10月14日消息,一个网络流行语的背后就是一个热点,有热点自然...
域名 转移密码多少?域名要想进行转移,需要获得转移密码。而转移密码,需要向原...
节省计划是一种折扣权益计划,您可以通过承诺在一定期限(1年或3年)内使用稳定...
在?Spring?Tools 4 for Eclipse 中依次选择 File-New-Maven Project,然后在出现...
1月22日,腾讯云正版曲库直通车宣布上线单曲产品,直播视频等创作者、MCN机构、...
安全组中为什么会默认有一条拒绝的规则? 安全组规则,是从上至下依次筛选生效的...
12月23日消息,据国际数据公司(IDC)近日发布的《中国云运营服务市场(2020上半年)...