关于集合Collection和映射Map遍历的一些思考

目录

几种遍历的底层:都是基于迭代器!

1.首先看看集合中的迭代器Iterator遍历:

简单介绍:

Collection接口实现类中ArrayList的源码,看看Iterator()怎么实现的

 2.增强for遍历的底层

举例如下:

遍历数组的情况:​编辑

遍历集合的情况:

3.forEach(java8新加的)遍历

 直接上源码:

         这里java8引入了 流Stream 的数据处理方式:

        4.Map中使用键值对遍历遇到的关于Map.Entry的思考​编辑

AbstractMap.SimpleEntry实现类:

 总结: 



几种遍历的底层:都是基于迭代器!

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构造函数创建其对象

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值