有位小朋友最近正在为年后换工作做准备,但是遇到一个问题,觉得很不可思议的一道笔试题。然后我把这道题发到技术群里,发现很多人居然不知道,很多都是连蒙带猜的说。感觉很有必要写一篇文章来说道说道。

有位小朋友最近正在为年后换工作做准备,但是遇到一个问题,觉得很不可思议的一道笔试题。然后我把这道题发到技术群里,发现很多人居然不知道,很多都是连蒙带猜的说。感觉很有必要写一篇文章来说道说道。


奇怪的笔试题阅读下面这段代码,请写出这段代码的输出内容:

import java.util.ArrayList;
import java.util.Iterator;
import java.util.*; public class Test { public static void main(String[] args) { List 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是什么?

迭代器是一种模式、详细可见其设计模式,可以使得序列类型的数据结构的遍历行为与被遍历的对象分离,即我们无需关心该序列的底层结构是什么样子的。只要拿到这个对象,使用迭代器就可以遍历这个对象的内部
Iterable 实现这个接口的集合对象支持迭代,是可以迭代的。实现了这个可以配合foreach使用~
Iterator 迭代器,提供迭代机制的对象,具体如何迭代是这个Iterator接口规范的。
Iterator说明

public interface Iterator {  //每次next之前,先调用此方法探测是否迭代到终点 boolean hasNext(); //返回当前迭代元素 ,同时,迭代游标后移 E next();  /*删除最近一次已近迭代出出去的那个元素。 只有当next执行完后,才能调用remove函数。 比如你要删除第一个元素,不能直接调用 remove()   而要先next一下( ); 在没有先调用next 就调用remove方法是会抛出异常的。 这个和MySQL中的ResultSet很类似 */ default void remove() { throw new UnsupportedOperationException("remove"); }  default void forEachRemaining(Consumer action) { Objects.requireNonNull(action); while (hasNext()) action.accept(next()); }
}

这里的实现类是ArrayList的内部类Itr。

private class Itr implements Iterator { 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()

第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。
第二个iterator.hasNext()

hasNext方法中:cursor==2, size==2,所以cursor != size返回false。

所以,最后只输出"4",即答案为4.

Iterator与泛型搭配

Iterator对集合类中的任何一个实现类,都可以返回这样一个Iterator对象。可以适用于任何一个类。
因为集合类(List和Set等)可以装入的对象的类型是不确定的,从集合中取出时都是Object类型,用时都需要进行强制转化,这样会很麻烦,用上泛型,就是提前告诉集合确定要装入集合的类型,这样就可以直接使用而不用显示类型转换.非常方便.

foreach和Iterator的关系

for each以用来处理集合中的每个元素而不用考虑集合定下标。就是为了让用Iterator简单。但是删除的时候,区别就是在remove,循环中调用集合remove会导致原集合变化导致错误,而应该用迭代器的remove方法。

使用for循环还是迭代器Iterator对比

采用ArrayList对随机访问比较快,而for循环中的get()方法,采用的即是随机访问的方法,因此在ArrayList里,for循环较快
采用LinkedList则是顺序访问比较快,iterator中的next()方法,采用的即是顺序访问的方法,因此在LinkedList里,使用iterator较快
从数据结构角度分析,for循环适合访问顺序结构,可以根据下标快速获取指定元素.而Iterator 适合访问链式结构,因为迭代器是通过next()和Pre()来定位的.可以访问没有顺序的集合.
而使用 Iterator 的好处在于可以使用相同方式去遍历集合中元素,而不用考虑集合类的内部实现(只要它实现了 java.lang.Iterable 接口),如果使用 Iterator 来遍历集合中元素,一旦不再使用 List 转而使用 Set 来组织数据,那遍历元素的代码不用做任何修改,如果使用 for 来遍历,那所有遍历此集合的算法都得做相应调整,因为List有序,Set无序,结构不同,他们的访问算法也不一样.(还是说明了一点遍历和集合本身分离了)。

总结

迭代出来的元素都是原来集合元素的拷贝。
Java集合中保存的元素实质是对象的引用,而非对象本身。
迭代出的对象也是引用的拷贝,结果还是引用。那么如果集合中保存的元素是可变类型的,那么可以通过迭代出的元素修改原集合中的对象。

迭代器笔试题,看看你会不会?相关推荐

  1. 华为校招java笔试题库_华为校招Java笔试题库,看你会不会做

    1.在java中如果声明一个类为final,表示什么意思? 答:final是最终的意思,final可用于定义变量.方法和类但含义不同,声明为final的类不能被继承. 2.父类的构造方法是否可以被子类 ...

  2. 十月下旬腾讯,网易游戏,百度盛大迅雷校园招聘笔试题集锦(10.25)

    十月下旬腾讯,网易游戏,百度最新校园招聘笔试题集锦 引言 笔试啊,笔试,面试啊,面试,找工作啊,找工作.此文十月百度,阿里巴巴,迅雷搜狗最新面试十一题已经整理了最新的面试题70道,本文依次整理腾讯,网 ...

  3. python面试题及答案bt_公布上期Python笔试题答案,附带源码与运行结果

    今天发布的内容没有废话,就是上一期的笔试题答案,由于内容较多,我们今天就公布前五道题的答案,附带源码哦!请感兴趣的读者细细研究! 笔试 笔试题一答案:利用Python创建如图所示的二叉树,并给出前序. ...

  4. 金九银十!2021阿里+头条+腾讯等大厂Java笔试题分享

    前言 时至今日, Spring在Java生态系统与就业市场上,面试出镜率之高,投产规模之广,无出其右.随着技术的发展,Spring从往日的IoC框架,已发展成Cloud Native基础设施,衍生出大 ...

  5. java笔试题_一道简单的 Java 笔试题,但值得很多人反思

    专注于Java领域优质技术,欢迎关注 作者:匿蟒 前言 面试别人,对我来说是一件新奇事,以前都是别人面试我.我清楚地知道,我在的地域与公司,难以吸引到中国的一流软件人才.所以,我特地调低了期望,很少问 ...

  6. python考试题目及答案-python面试真实笔试题,带答案(1-10题)

    最近从各种python微信群收集了100多道真实的python面试笔试题,因为都是真实题目,故没有答案,为了给那些即将面试的好友提供一份帮助,也为了给广大好友巩固基本python语法知识,最近将把收集 ...

  7. ⑪(面试篇 2/3)、《史上最全iOS八股文面试题》2022年,金三银四我为你准备了,iOS《1000条》笔试题以及面试题(包含答案)。带面试你过关斩将,(赶紧过来背iOS八股文)

    iOS面试题 一共分为笔试题和面试题两部分 笔试题 一共分为10个 总共613题 面试题 一共400题 笔试题 一个10个系列 分别为 ①(语法篇) 共147题 已更新 ②(常识篇) 共72题 已更新 ...

  8. JAVA面试、笔试题

    @[TOC]目录 JAVA面试.笔试题 @目录 一. CoreJava部分 7 1. java中有哪些基本类型? 7 2. java反射 7 3. 易错,理解题 7 4. Java有几种创建对象的方法 ...

  9. 换了个地方,来北京工作,面试了4家python爬虫,写一些这四家(记得的)笔试题(2)

    1.Python是如何进行内存管理的? 答:从三个方面来说,一对象的引用计数机制,二垃圾回收机制,三内存池机制 一.对象的引用计数机制 Python内部使用引用计数,来保持追踪内存中的对象,所有对象都 ...

最新文章

  1. LibreOffice使用笔记
  2. 设置socket IP_TOS选项 (转载)
  3. Uri跟Url的区别
  4. asp.net session 如何知道是哪个浏览器客户端_微服务下的分布式session管理
  5. DCMTK:演示状态查看器-后台打印程序
  6. 我所有的博客都在这里了,拿出来晒晒~~
  7. Python-流程控制之循环
  8. 13-StringTable
  9. getopt在Python中的使用
  10. pointer-events:none解决重叠元素不能感应鼠标事件的问题
  11. Python基础知识题库(带答案)
  12. 诛仙服务器 修改技能伤害,《诛仙3》技能调整优化【 技能修改·天脉】
  13. word方式编辑EPUB电子书
  14. 尚硅谷周阳老师 - Docker课程学习
  15. 新手云服务器系统,新手云服务器系统
  16. HTML+CSS基础训练之实现一个“真实”的网页~
  17. 2021年中国汽车产量、销量及汽车制造业发展趋势分析[图
  18. 基于 WebRTC 的 P2P 文件传输
  19. 树的结点?结点的度?
  20. spring框架学习 - 使用 Spring 的面向切面编程补充

热门文章

  1. 为了爱情,吃掉150瓶“老干妈”的程序员
  2. Dubbo基础专题——第二章(Dubbo工程简单实践)
  3. 用户组管理之更新分组表数据
  4. MySQL WindowsCMD常用命令!
  5. ACMNO.5给出一百分制成绩,要求输出成绩等级‘A’、‘B’、‘C’、‘D’、‘E’。 90分以上为A 80-89分为B 70-79分为C 60-69分为D 60分以下为E
  6. 基于YOLOv3和PyTorch 的视频-图像模型
  7. 创建Joomla菜单
  8. 利用IPSec实现网络安全之三(身份验证和加密数据)
  9. rabbitmq学习——安装测试
  10. 《从缺陷中学习C/C++》——6.15 试图产生的指针很可能不存在