面试题:简述什么是迭代器(Iterator)?
一、什么是Iterator?
迭代器(Iterator)是一个专门用来遍历集合(如数组、列表等)中的元素的对象。它可以帮助开发者按照一定的规则顺序访问集合中的每一个元素,而无需了解集合内部的实现细节。可以简单理解为迭代器是一个“导航员”,负责帮你从头到尾“走遍”整个集合。
为什么需要迭代器?
在迭代器出现之前,我们通常是直接使用集合的内部结构进行遍历,例如:
1. 使用数组
int[] arrays = new int[10];
for (int i = 0; i < arrays.length; i++) {
int a = arrays[i];
// 处理元素
}
2. 使用列表(如 ArrayList)
List<String> list = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
String string = list.get(i);
// 处理元素
}
这种方式的问题在于:
- 遍历逻辑和集合结构绑定得很紧密,耦合性高。
- 每种集合(如数组、列表)需要使用不同的遍历方式,代码难以复用。
- 如果集合类型发生变化(例如从 ArrayList 切换为 LinkedList),还需要修改遍历代码,非常麻烦。
**为了解决这些问题,Iterator 应运而生。**它提供了一种统一的遍历逻辑,屏蔽了集合的内部实现细节。
Iterator 的作用
迭代器通过一些简单的操作(比如“向前”、“取当前元素”等),可以轻松实现对集合的遍历。开发者只需专注于业务逻辑,无需关心集合是如何存储数据的。
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String string = iterator.next();
// 处理元素
}
二、java.util.Iterator
的基本接口
在 Java 中,Iterator
是一个接口。它定义了对集合进行遍历的基本规则。Iterator
的接口代码如下:
public interface Iterator {
boolean hasNext(); // 判断是否有下一个元素
Object next(); // 返回下一个元素
void remove(); // 删除当前元素
}
方法说明:
-
boolean hasNext()
检查集合中是否还有未访问的元素,返回true
表示还有,false
表示没有了。 -
Object next()
返回集合中当前指针指向的元素,并将指针移到下一个位置。如果没有元素了,会抛出NoSuchElementException
。 -
void remove()
删除最近一次调用next()
返回的元素。注意,这个方法需要谨慎使用,如果调用顺序不正确(比如连续调用两次remove()
),会抛出IllegalStateException
。
三、各集合中 Iterator 的实现
不同集合的 Iterator 实现逻辑可能不同,但使用方式对开发者是透明的。以 ArrayList
为例:
ArrayList 的 Iterator 实现
在 ArrayList
中,有一个内部类 Itr
,它实现了 Iterator
接口。以下是简化后的核心代码:
private class Itr implements Iterator<E> {
int cursor; // 当前元素的索引位置
int lastRet = -1; // 上一个访问元素的索引位置,-1 表示没有
public boolean hasNext() {
return cursor != size; // 判断是否还有元素未访问
}
public E next() {
if (cursor >= size) throw new NoSuchElementException();
return (E) elementData[lastRet = cursor++];
}
public void remove() {
if (lastRet < 0) throw new IllegalStateException();
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
}
}
快速失败机制
在 Java 的集合中,有一个机制叫 快速失败(Fail-Fast),它用来检查集合在遍历过程中是否被修改了。如果检测到集合的内容被其他线程或代码修改,就会抛出 ConcurrentModificationException
,以防止错误结果。
在 ArrayList
中,这通过 modCount
实现。当集合被修改时,modCount
会增加。如果 Iterator
遍历过程中发现 modCount
发生了变化,就会抛出异常。
四、ListIterator 的扩展
除了基本的 Iterator
,还有一个更强大的迭代器——ListIterator
,专门用于 List
类型集合的遍历。与 Iterator
的区别在于,ListIterator
可以:
- 双向遍历(通过
previous()
方法向前遍历)。 - 在遍历过程中插入或修改元素。
示例代码:
List<String> list = new ArrayList<>();
ListIterator<String> listIterator = list.listIterator();
while (listIterator.hasNext()) {
String element = listIterator.next();
listIterator.set(element + "_updated"); // 修改元素
}
五、三种遍历方式对比
1. 使用方式
For 循环
for (int i = 0; i < list.size(); i++) {
String element = list.get(i);
// 处理元素
}
For-Each
for (String element : list) {
// 处理元素
}
Iterator
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String element = iterator.next();
// 处理元素
}
2. 区别
方式 | 优点 | 缺点 |
---|---|---|
For 循环 | 简单,适合有序集合(如数组) | 与集合结构耦合,代码可读性差 |
For-Each | 简洁,避免索引越界问题 | 无法修改或删除元素 |
Iterator | 解耦、统一遍历逻辑,可删除元素 | 写法稍复杂 |
3. 性能对比
- ArrayList:随机访问快,因此 For 循环效率高。
- LinkedList:顺序访问快,因此 Iterator 效率更高。
六、总结
迭代器(Iterator)是遍历集合的强大工具。它的主要优点在于:
- 解耦遍历逻辑与集合实现,代码更灵活。
- 支持删除和修改元素操作。
- 适合各种集合类型,包括有序和无序集合。
当你只需要简单遍历时,For-Each 是最简单的选择;但如果需要修改集合或者操作链式结构的集合,Iterator 无疑是最好的工具。
最后说一句(求关注,求赞,别白嫖我)
最近无意间获得一份阿里大佬写的刷题笔记,一下子打通了我的任督二脉,进大厂原来没那么难。
这是大佬写的 7701页的BAT大佬写的刷题笔记,让我offer拿到手软
本文,已收录于,我的技术网站 cxykk.com:程序员编程资料站,有大厂完整面经,工作技术,架构师成长之路,等经验分享
求一键三连:点赞、分享、收藏
点赞对我真的非常重要!在线求赞,加个关注我会非常感激!