小白学Java:迭代器原来是这么回事

前文传送门:Enumeration

上一篇,我们谈到了那个古老的迭代器Enumeration,还谈到了取代他的新迭代器——Iterator。相比于以往,这个新物种又有哪些优点呢?

迭代器这个词,在没查找许多资料之前,我只知道个大概,我知道它可以用来遍历集合,但是至于它其中的奥妙,并没有做深究。本篇文章关于Iterator迭代器做了小小的总结,巩固学习,如果有理解错误,或叙述不当之处,还望大家评论区批评指针。

迭代器概述

官方文档对Iterator的解释是:

  • 它取代了Enumeration。
  • 它作用于任何一个Collection。
  • 它增加了remove的功能。
  • 它优化了方法命名。

不行不行,这描述也太简略了,我继续查找资料:

  • 迭代器本身是个对象,创建迭代器的代价很小,通常被称为轻量级对象
  • 迭代器其实也是一种设计模式,它提供了一种方法顺序访问一个聚合对象中的各个元素,但又不暴露该对象的内部表示。

迭代器设计模式

针对以上种种,我充满了好奇,于是在复杂的继承关系里画了又画,最终才渐渐理清集合中所谓迭代器模式的体现,暂时以ArrayList为例:

  • 定义了一个迭代器的接口Iterator,里面定义了迭代器的功能,但并没有提供实现。
  • 定义了一个聚集接口Iterable,里面的iterator()抽象方法,表明返回一个针对类型T的迭代器。此时将Iterable和Iterator联系了起来。
  • 我们知道聚集接口被许多接口所扩展,定义相同的方法,Collection接口就是其一,所以说,迭代器针对于所有集合都有效。
  • 我们以集合的具体类ArrayList为例,暂时忽略之间的继承关系,ArrayList显然提供了抽象方法iterator()的具体实现,我们查看源码发现,它的返回值是一个Itr对象。
  • 这个Itr其实是ArrayList的一个内部类,它提供了迭代器接口的具体实现(当然不一定是内部类),这样所有东西都联系在了一起。

Iterator定义的方法

  • hasNext():boolean 判断下一个元素还有没有,有就是true。
  • next(): E 返回序列中的下一个元素。

通过查看源码,我发现,在这个Itr这个实现类中,定义了两个指针:cursorlastRet。(还有个属性为expectedModCount初始化为ArrayList的版本号modCount,这部分与fail-fast机制相关,之后会再提)而cursor初始为0,与专门用来和集合元素数目size做比较的。而lastRet初始化为-1,如果成功执行next操作,将会加1变成0,也就是上面说的“下一个元素”可想而知,可以把lastRet认为是初始化为第一个元素之前的指针,和将要返回的值的索引相同,这样会好记一些。

除了上面两个方法,JDK1.8新增了两个方法,也是体现处它与老迭代器不同的新优势:支持了删除操作。

  • remove():void 将新近返回的元素删除。

    需要注意的是:remove方法没有新近返回的元素,也就是说lastRet<0,会抛出异常。如果移除成功,让cursor往回退一格,lastRet重置为-1。

  • forEachRemaining(Consumer<? super E> consumer):void 这个是JDK1.8中Iterator新增的默认方法:对剩余的元素执行指定的操作

    可能不太好理解:我们通过测试来说明一下:

    List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
//创建一个Iterator对象
Iterator<Integer> it = list.iterator();
//返回第一个值
System.out.print(it.next()+" ");

测试结果很明显,只输出了第一个元素:1。

我们继续在原代码的基础上我们的新方法:

    it.forEachRemaining(new Consumer<Integer>() {
@Override
public void accept(Integer integer) {
System.out.print(integer+" ");
}
});

测试结果为:1 2 3,在原来的基础上,把剩下的元素都打印了出来。而这个新增的方法,其实和我们熟悉的这个是一样的:

    while(it.hasNext()){
System.out.print(it.next()+" ");
}

值得一提的是:我们之前学习的增强for循环,在底层其实就是运用了Iterator,我通过IDE的debug调试功能,发现在调用运行到增强for循环时,自动调用了集合的iterator()方法,返回了一个Iterator的实现类实例。

迭代器:统一方式

通过对Iterator中定义方法的学习,我们大概知道了迭代器的用途,就是从前向后一个一个遍历元素,而无视其内部结构。欸,遍历我都懂,可无视结构在哪里体现啊?别急,下面来看一个例子,让我们无视两个不同集合的结构:

首先我们定义一个方法,它可以接收一个迭代器对象:

    public static void display(Iterator<?> T){
while(T.hasNext()){
System.out.print(T.next());
}
}

然后我们创建两个不一样的集合,一个是ArrayList,一个是HashSet,本身是无序的,我们接下来应该会做相应的源码学习。

        //ArrayList 有序
List<String> list = new LinkedList<>();
list.add("天");
list.add("乔");
list.add("巴");
list.add("夏");
//HashSet 无序
Set<Integer> set = new HashSet<>();
set.add(11);
set.add(22);
set.add(33);
set.add(44);
display(list.iterator());//天 乔 巴 夏
System.out.println();
display(set.iterator());//33 22 11 44

可以看出来,两个不同集合的迭代器传入display方法之后,都能用一种相同的方式访问集合中的元素。

通过上面的一顿分析,我们可以确定,迭代器这玩意儿,统一了访问容器的方式

Iterator的总结

  • Iterator支持从前向后顺次遍历,统一了对不同集合里元素的操作
  • 还在Enumeration的基础上,简化了命名,而且Enumeration并不是对所有集合都适用。
  • 四大技能增删改查,虽然支持删和查,但不支持增和改。
  • 支持单向迭代,某些情况下不是很灵活。(ListIterator可以支持双向,但只支持List类型)

最后,关于迭代器,还有一部分内容,在日后会做总结。

参考资料:《大话设计模式》、《Java编程思想》

小白学Java:迭代器原来是这么回事的更多相关文章

  1. 小白学Java:奇怪的RandomAccess

    目录 小白学Java:奇怪的RandomAccess RandomAccess是个啥 forLoop与Iterator的区别 判断是否为RandomAccess 小白学Java:奇怪的RandomAc ...

  2. 小白学Java:内部类

    目录 小白学Java:内部类 内部类的分类 成员内部类 局部内部类 静态内部类 匿名内部类 内部类的继承 内部类有啥用 小白学Java:内部类 内部类是封装的一种形式,是定义在类或接口中的类. 内部类 ...

  3. 小白学Java:I/O流

    目录 小白学Java:I/O流 基本分类 发展史 文件字符流 输出的基本结构 流中的异常处理 异常处理新方式 读取的基本结构 运用输入与输出 文件字节流 缓冲流 字符缓冲流 装饰设计模式 转换流(适配 ...

  4. 小白学Java:包装类

    目录 小白学Java:包装类 包装类的继承关系 创建包装类实例 自动装箱与拆箱 自动装箱 自动拆箱 包装类型的比较 "=="比较 equals比较 自动装箱与拆箱引发的弊端 自动装 ...

  5. 小白学Java:老师!泛型我懂了!

    目录 小白学Java:老师!泛型我懂了! 泛型概述 定义泛型 泛型类的定义 泛型方法的定义 类型变量的限定 原生类型与向后兼容 通配泛型 非受限通配 受限通配 下限通配 泛型的擦除和限制 类型擦除 类 ...

  6. 小白学Java:File类

    目录 小白学Java:File类 不同风格的分隔符 绝对与相对路径 File类常用方法 常用构造器 创建方法 判断方法 获取方法 命名方法 删除方法 小白学Java:File类 我们可以知道,存储在程 ...

  7. 小白学Java:RandomAccessFile

    目录 小白学Java:RandomAccessFile 概述 继承与实现 构造器 模式设置 文件指针 操作数据 读取数据 read(byte b[])与read() 追加数据 插入数据 小白学Java ...

  8. 【aliyun】学java,看这里,不迷茫!1460道Java热门问题

    阿里极客公益活动: 或许你挑灯夜战只为一道难题 或许你百思不解只求一个答案 或许你绞尽脑汁只因一种未知 那么他们来了,阿里系技术专家来云栖问答为你解答技术难题了 他们用户自己手中的技术来帮助用户成长 ...

  9. 浅谈Java迭代器

    迭代器Iterator 概述: 迭代器(Iterator):它不是一个容器,它是一种用于访问容器的方法,可用于迭代 List.Set和Map等容器. 迭代:一个一个的往外拿. 作用:帮我们遍历或者拿到 ...

随机推荐

  1. 【u227】BOOK

    Time Limit: 1 second Memory Limit: 128 MB [问题描述] 陈老师喜欢网购书籍,经常一次购它个百八十本,然后拿来倒卖,牟取暴利.前些天,高一的新同学来了,他便像往 ...

  2. [转]WebApi 后端文件传输至远程服务器

    /* 功能说明:微信退款需要有数字证书,而我们公司是做小程序平台的,会帮商家自动退款,所以会要求商家把微信证书上传至我们服务器,以便 微信退款. 使用HttpPostedFile 接受前端上传的文件, ...

  3. Python--day38--JoinableQueue解决生产者消费者模型

    ############################# # 在消费者这一端: #每次获取一个数据 #处理一个数据 #发送一个记号:标志一个数据被处理成功 #在生产者这一端: #每一次生成一个数据 ...

  4. AWS Credentials 使用

    AWS的文档系统真是烂到家了!!!!! To connect to any of the supported services with the AWS SDK for Java, you must ...

  5. H3C 配置静态及动态域名解析

  6. AI百度接口以及图灵接口的使用

    百度AI接口 AI智能种类方向 耳朵 = 倾听 = 麦克风 = 语音识别 ASR:Automatic Speech Recognition 嘴巴 = 诉说 = 扬声器 = 语音合成 TTS:Text ...

  7. H3C VLAN显示及维护

  8. vue-learning:12-1- HTML5的<template>内容模板元素

    HTML5的<template>内容模板元素 HTML内容模板<template>元素将它其中的内容存储在页面文档中,以供后续使用,该内容的DOM结构在加载页面时会被解析器处理 ...

  9. python 练习题3

    # 计算阶乘def factorial(n): if n>2: return n*factorial(n-1) else: return nprint(factorial(2))print(fa ...

  10. STM32 命名方法

    1.STM32型号的说明:以STM32F103RBT6这个型号的芯片为例,该型号的组成为7个部分,其命名规则如下: STM32  ST公司生产的Cortex-M内核的32位微控制器 F F代表产品类型 ...