目录
Collection接口实现类中ArrayList的源码,看看Iterator()怎么实现的
4.Map中使用键值对遍历遇到的关于Map.Entry的思考编辑
几种遍历的底层:都是基于迭代器!
1.首先看看集合中的迭代器Iterator遍历:
简单介绍:
通常我们都是通过Collection接口中的方法Iterator()返回的Itreator来创建迭代器对象,得到迭代器对象后,再通过一个while循环,调用hasNext()判断游标Cusor指向的当前位置有无元素,调用next()寻找集合中下一个元素并返回游标Cusor指向的上一个位置的元素,直到迭代器的游标指向空才停止
大致如下:
注意,Iterator也要加泛型,因为iterator.next()返回值是泛型类型
此外,还要知道,如果我们已经通过Iterator()返回的一个迭代器对象遍历过集合,还想要遍历一次的话就必须重新创建一个,就类似于象棋中的兵,不能回头,遍历完的迭代器对象就没用了
Java 中的迭代器对象通常会维护一个对原始集合对象的弱引用,当你不再持有迭代器对象时,垃圾回收器会自动将其回收。如果你手动销毁迭代器对象,则可能会引发不必要的内存泄漏或垃圾回收问题。
Collection接口实现类中ArrayList的源码,看看Iterator()怎么实现的
我们可以从ArrayList源码中很清楚的的看到,ArrayList为了实现Iterator接口: 提供的Iterator()方法实际上就是返回了一个Itr对象,而Itr类是ArrayList的内部类,用于实现Iterator接口
所以我们每次通过迭代器对象遍历ArrayList集合的时候,其实就是创建了一个内部类Itr的对象。又因为迭代器无法回头的特性,所以再次遍历就要再次调用Iterator方法创建新的Itr对象
2.增强for遍历的底层
我们知道增强for的格式如下:
for (元素类型 变量名 : 集合或数组) {
// 循环体
}
举例如下:
遍历数组的情况:

其实上面增强for代码实际编译时会转化为以下代码
但是实际上,数组会被转为与之对应的集合,再使用迭代器遍历。数组索引就换成了迭代器的游标cusor,也就是调用next()方法。本质上还是用得迭代器进行遍历
遍历集合的情况:
实现过程就是迭代器遍历,比如如下的增强for编译时会转换为:
↓
综上,增强for其实也就是迭代器遍历的另一种表达方式,采用了更简洁易懂的语法
3.forEach(java8新加的)遍历
直接上源码:
这里java8引入了 流Stream 的数据处理方式:
Stream API提供了一种类似于SQL语句的流式操作方式,可以对集合(Collection)、数组等进行数据的筛选、排序、映射、分组等操作,使得数据处理更加高效、简洁、易读。Stream API最大的特点就是支持链式调用,可以将多个操作串联在一起形成一个流水线式的处理过程。
而Stream API的底层实现使用了迭代器(Iterator)和函数式接口(Functional Interface)的概念。Stream API中的流是对集合或数组等数据源的抽象,通过对数据源进行封装,使得数据的处理可以更加高效。
这里看到源码中有for(T t : this)这样一个增强for的循环遍历,操作对象是函数式接口Consumer(用于接收一个输入参数并且不返回任何结果。forEach循环中Consumer
接口的accept
方法会被回调,对每个元素执行指定的操作。)接收到的数据。
同时,因为有函数式接口,所以也可以通过Lambda表达式进一步化简,关于Lambda表达式,在我的一篇文章中提到过:Lambda表达式的基本使用
所以,forEach实际上底层也是基于迭代器
4.Map中使用键值对遍历遇到的关于Map.Entry的思考
这里我是先通过Map调用entrySet()创建一个set集合用来存储 所有键值对 对象。
在迭代器便利的时候我发现,因为我们需要一个中间变量来存储Entry对象,但是Map.Entry<>是一个接口,无法创建对象,于是我开始疑惑,我创建的es到底是什么数据类型。
后来我想到HashMap和TreeMap是Map的实现类,会不会es是其中一个类型的呢
我有查看了HashMap的源码,发现了他里面的Node类实现了Entry接口,于是我尝试以下的写法来创建
但是报错:
被告知不是public,虽然是static类型不能直接外部访问。
既然HashMap不行,那我就去看了下TreeMap源码
发现,TreeSet内有Entry这一内部类,用于创建私有成员变量。
因此,很显然Map.Entry<>创建的es对象也不是TreeSet类型。
AbstractMap.SimpleEntry实现类:
最终我查阅资料,发现Map.Entry<>创建的对象实际上是(多态思想,可以参考我的一篇文章:类的多态,可以触类旁通接口和实现类的多态)AbstractMap.SimpleEntry类型的,而它是Entry接口的简单实现类,内部只有两个成员变量Key和Value。
查看AbstractMap的源码,发现它里面确实存在一个内部类SimpleEntry实现了Entry接口,成员变量只有键和值
总结:
1.对于集合Collection和映射Map的底层遍历方式,其实都是基于迭代器实现的
2.我们在使用Map.Entry<>创建对象的时候,实际上就是利用多态思想,调用AbstractMap.SimpleEntry构造函数创建其对象