面试官不按套路出牌,上来就让聊一聊Java中的迭代器(Iterator ),夺命连环问,怎么办?
写在开头
某大厂的面试现场,一位目光深邃,头顶稀疏的中年面试官坐在椅子上,这时候的我走了进来。
面试官:“小伙子,学过Java中容器和数据结构了吧?”
我:“嗯,学了”
面试官:“ok,那你来聊一聊Java中的迭代器(Iterator ),要说清楚他们的应用场景哈”
我:“哦,好滴”
内心独白:“这面试官不按套路出牌啊,本来以为会问问ArrayList,HashMap呢,或者手撕排序算法,这上来直接让撕迭代器”
虽然面试官不按套路出牌,但这时我们也不能乱,迅速的平复心情后,大脑飞速运转,回想着之前学的内容,其实迭代器和比较器确实在容器和数据结构中有所体现。
Iterator (迭代器)
在解释迭代器之前,我们先来聊一下23种设计模式之一:迭代器模式,它是 Java 中常用的设计模式之一。用于顺序访问集合对象的元素,无需知道集合对象的底层实现。
而Iterator则是在这种设计思想下诞生的产物,Iterator 是可以遍历集合的对象,为各种容器提供了公共的操作接口,隔离对容器的遍历操作和底层实现,从而解耦。
【源码解析1】
public interface Iterator<E> {
//是否有下一个元素
boolean hasNext();
//下一个元素
E next();
//从迭代器指向的集合中删除迭代器返回的最后一个元素
default void remove() {
throw new UnsupportedOperationException("remove");
}
//遍历所有元素
default void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (hasNext())
action.accept(next());
}
}
那我们日常使用中如何通过迭代器去遍历集合中的数据呢?我们接下往下看(一步一步耐心的给面试官解释,不要紧张,保持逻辑清楚!)
【代码示例1】
public class Test {
public static void main(String[] args) {
ArrayList<String> str = new ArrayList<>();
str.add("aaa");
str.add("bbb");
str.add("ccc");
//迭代器遍历
Iterator it = str.iterator();
while (it.hasNext()) {
System.out.print(it.next() + ",");
}
}
}
输出:
aaa,bbb,ccc,
我们创建一个包含ArrayList容器,里面包含aaa,bbb,ccc元素,通过调用str对象的iterator()方法去遍历元素,然后将遍历的元素打印出来,如上输出(这部分可以手撕给面试官看,方便后续的展开阐述)
面试官:“那你知道为什么ArrayList可以调用迭代器方法吗,底层逻辑有没有看过?”
当面试官问到这个问题的时候,我们心中一喜,因为他成功的被我们引导到了我们熟悉的方向上,那么接下来,我们要好好唠一唠了!
我:“嗯,之前学习的时候,有跟过这部分底层源码,我说说看,不对的麻烦您多给指正哈”
我们知道Collection是Set、List、Queue的父接口,而Collection接口又继承了另外一个接口,叫Iterable,得到了它的一个接口方法iterator()。
【源码解析2】
public interface Collection<E> extends Iterable<E> {
...
Iterator<E> iterator();
...
而对于我们日常使用的集合类来说,如ArrayList,它的继承关系让它可以得到iterator对象,我们可以画一个流程图来分析一下。

ArrayList中重写了AbstractList中的iterator()方法,并返回一个内部类对象Itr,我们看一下这个内部类的实现源码。
【源码解析3】
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;
}
@SuppressWarnings("unchecked")
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
@Override
@SuppressWarnings("unchecked")
public void forEachRemaining(Consumer<? super E> consumer) {
Objects.requireNonNull(consumer);
final int size = ArrayList.this.size;
int i = cursor;
if (i >= size) {
return;
}
final Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length) {
throw new ConcurrentModificationException();
}
while (i != size && modCount == expectedModCount) {
consumer.accept((E) elementData[i++]);
}
// update once at end of iteration to reduce heap write traffic
cursor = i;
lastRet = i - 1;
checkForComodification();
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
讲到这里,我们可以给一个阶段性的总结:所以在继承了Collection接口,并实现了iterator()方法的所有集合类,都可以使用迭代器进行元素的遍历。
【温馨提示】
若此时的你足够强大,足够自信,还可以进一步引出增强for循环遍历,它的底层原理也是Iterator
【代码示例2】
for (String str : list) {
System.out.print(str + ",");
}
【反编译】
Iterator var3 = list.iterator();
while(var3.hasNext()) {
String str = (String)var3.next();
System.out.print(str + ",");
}
反编译后我们可以看得出,底层的实现就是迭代器,而这个for-each的写法不过是Java的一个语法糖罢了,这部分属于附加题,讲不明白的,可以不提。
本来以为迭代器这个话题到此就结束了,没想到面试官紧接着又抛出了一个问题
面试官:“LinkedList也是如此吗?”
听到这里咱们心里一紧,他终究是要挖光我们的家底呀
确实!LinkedList有所不同,LinkedList 并没有直接重写 Iterable 接口的 iterator 方法,而是由它的父类 AbstractSequentialList 来完成。
进入源码会发现,这个AbstractSequentialList 中提供了一个listIterator对象,而LinkedList进行了方法的重写。
【源码解析4】
public interface ListIterator<E> extends Iterator<E> {
boolean hasNext();
E next();
boolean hasPrevious();
E previous();
}
这让它拥有了可以从任意下标开始遍历,而且支持双向遍历的能力。注意ListIterator只支持List类型集合。
到此,我们对于Iterator的了解全盘拖出了,当然还有一些细枝末节的知识,但我相信能回答到这里,已经获得面试官的认可啦。
结尾彩蛋
如果本篇博客对您有一定的帮助,大家记得留言+点赞+收藏呀。原创不易,转载请联系Build哥!

面试官不按套路出牌,上来就让聊一聊Java中的迭代器(Iterator ),夺命连环问,怎么办?的更多相关文章
- 面试官不按套路,竟然问我Java线程池是怎么统计线程空闲时间?
背景介绍: 你刚从学校毕业后,到新公司实习,试用期又被毕业,然后你又不得不出来面试,好在面试的时候碰到个美女面试官! 面试官: 小伙子,我看你简历上写的项目中用到了线程池,你知道线程池是怎样实现复用线 ...
- 面试官:小伙子,你给我说一下Java中什么情况会导致内存泄漏呢?
概念 内存泄露:指程序中动态分配内存给一些临时对象,但对象不会被GC回收,它始终占用内存,被分配的对象可达但已无用.即无用对象持续占有内存或无用对象的内存得不到及时释放,从而造成的内存空间浪费. 可达 ...
- 字节跳动Android春招,三轮面试,夺命连环问,心态崩了
我是春招参加字节面试的,现在已经入职俩月啦,当时没有及时记录下来拖到现在...我尽量回忆当时的内容希望能帮到大家. 投的部门是深圳字节影像,不得不说这个部门的效率,上午投下午就接到hr的电话约面试时间 ...
- 面试官:小伙子,你给我说一下Java Exception 和 Error 的区别吧?
前言 昨天在整理粉丝给我私信的时候,发现了一个挺有意思的事情.是这样的,有一个粉丝朋友私信问我Java 的 Exception 和 Error 有什么区别呢?说他在面试的时候被问到这个问题卡壳了,最后 ...
- 面试官提出的问题应该怎么答?(如开发中使用过EasyUI吗?)
Jquery EasyUI是第三方基于Jquery框架开发的一款轻量级的,侧重于页面显示部分的框架,也可以称为插件. Jquery EasyUI使用比较简单,也有比较全的文档可供参考. 常用的组件就是 ...
- 面试官:小伙子,你给我讲一下java类加载机制和内存模型吧
类加载机制 虚拟机把描述类的数据从 Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的java类型,这就是虚拟机的类加载机制. 类的生命周期 加载(Loadi ...
- 阿里面试官:HashMap 熟悉吧?好的,那就来聊聊 Redis 字典吧!
最近,小黑哥的一个朋友出去面试,回来跟小黑哥抱怨,面试官不按套路出牌,直接打乱了他的节奏. 事情是这样的,前面面试问了几个 Java 的相关问题,我朋友回答还不错,接下来面试官就问了一句:看来 Jav ...
- 面试官又整新活,居然问我for循环用i++和++i哪个效率高?
原创:微信公众号 码农参上,欢迎分享,转载请保留出处. 前几天,一个小伙伴告诉我,他在面试的时候被面试官问了这么一个问题: 在for循环中,到底应该用 i++ 还是 ++i ? 听到这,我感觉这面试官 ...
- 你所不知道的 CSS 阴影技巧与细节 滚动视差?CSS 不在话下 神奇的选择器 :focus-within 当角色转换为面试官之后 NPOI 教程 - 3.2 打印相关设置 前端XSS相关整理 委托入门案例
你所不知道的 CSS 阴影技巧与细节 关于 CSS 阴影,之前已经有写过一篇,box-shadow 与 filter:drop-shadow 详解及奇技淫巧,介绍了一些关于 box-shadow ...
- 《吊打面试官》系列-ConcurrentHashMap & HashTable
你知道的越多,你不知道的越多 点赞再看,养成习惯 本文 GitHub https://github.com/JavaFamily 已收录,有一线大厂面试点思维导图,也整理了很多我的文档,欢迎Star和 ...
随机推荐
- [转帖]CoreDNS loop 插件异常问题
https://zhuanlan.zhihu.com/p/476611162 背景 最近有遇到一个客户集群,发现集群中的 CoreDNS 老是异常 (loop 插件检测到有回路后进行 panic) ...
- [转帖]JMETER结果分析
https://www.cnblogs.com/a00ium/p/10462892.html 我相信你同意:有很多方法可以收集和解释JMeter结果,你会感到迷茫. 嗯,看完这篇文章后,您将了解收集和 ...
- [转帖]kafka压测多维度分析实战
设置虚拟机不同的带宽来进行模拟压测 ---------kafka数据压测-------------------1.公司生产kafka集群硬盘:单台500G.共3台.日志保留7天. 1. ...
- [转帖]linux块I/O总体概括
直接先上重点,linux中IO栈的完全图如下: 系统中能够随机访问固定大小数据片的硬件设备称作块设备.固定大小的数据片称为块.常见的块设备就是硬盘了.不能随机访问的就是字符设备了,管理块设备比字符设备 ...
- Mark 一下 Redisson 可能需要升级版本
貌似有bug 我们高并发的情况下貌似遇到了 https://github.com/redisson/redisson/issues/2299
- React Hooks源码深度解析
作者:京东零售 郑炳懿 前言 React Hooks是React16.8 引入的一个新特性,它允许函数组件中使用state和其他 React 特性,而不必使用类组件.Hooks是一个非常重要的概念,因 ...
- elementui中自定义Select选择器样式自定义
<el-select class="my-el-select" v-model="tenantCont" placeholder="请输入机构标 ...
- Gin 框架之jwt 介绍与基本使用
目录 一.JWT 介绍 二.JWT认证与session认证的区别 2.1 基于session认证流程图 2.2 基于jwt认证流程图 三. JWT 的构成 3.1 header : 头部 3.2 pa ...
- IDM全版本激活工具
前往IDM官网下载IDM IDM官网 下载破解工具 IDM激活工具.zip 解压打开激活工具选择1 然后回车耐心等待激活完成即可
- Pytest 源码解读 [1] - [pluggy] 核心设计理念浅读
背景: Pytest 是一个功能强大的 Python 测试框架,它使用了一个名为 "pluggy" 的插件系统来扩展其功能.在 Pytest 的源码中,pluggy 模块负责实现插 ...