Java迭代器【设计模式之迭代器模式】
目录
一.前言
二.正文
1.我写的类为什么不能使用增强for(迭代器遍历)
2.代码健全性——迭代器常见的两个Exception
1.NoSuchElementException
2.ConcurrentModificationException
三.后言
一.前言
本篇面向对象主要为和我一样的小白,主要是对迭代器模式的浅析和实现,会以大家最常见的ArrayList作为举例也会带着大家去分析一下源码,为了便于理解尽量口语化
本篇采用Kotlin代码,但以Java源码进行解析,因为首先最近实习一直在用Kotlin,其次这两个语言真的太像了,甚至源码都能说很多一样,想让大家可以注意到这门语言。
Kotlin 是一种在 Java 虚拟机(JVM)上运行的静态类型编程语言,由 JetBrains 开发,Kotlin 代码更为简洁,减少了样板代码,能让开发者以更少的代码实现相同功能。
二.正文
1.我写的类为什么不能使用增强for(迭代器遍历)
增强for循环相信大家都写过,如下图:
这样我们可以访问list中的每一个元素,接下来我们定义一个Student类来试试
Student类中有name和age两个属性 
下图可以看到我们对student对象使用增强for失败了,那这是为什么呢,那么,我们就要去ArrayList里面找找原因了,去找找这个for
ArrayList实现的上级接口是Collection:
可以看到Collection继承了Iterable接口,我们接近跟进,我们找到了增强for,这段英文的大概意思是实现了这个接口那么对象就可以使用增强for
那好办了,那我就让Student类实现这个接口试试呗,泛型就随便填个String,继承这个接口需要重写iterator方法,这个方法返回Iterator对象,返回的这个其实就是迭代器对象
我们跟进 Iterator接口,可以看到里面有next方法和hasNext方法
而我们又知道增强for循环的另一种写法也就是迭代器遍历(增强for的底层就是调用迭代器遍历),看两个函数的返回类型我们就可以猜到,hasNext函数返回布尔类型用于循环判断条件,next用于拿取元素,那我们先写一个迭代器遍历的代码,然后来简单看看ArrayList是怎么实现这几个方法的
进入iterator方法,可以看到iterator方法返回了一个对象

这个对象是ArrayList的一个内部类,也就是说ArrayList通过调用iterator方法获取迭代器其实是得到了Itr对象,这个内部类实现了Iterator接口,所以重写了next方法和hasNext方法,不必了解太多,后面再分析源码,你只要知道这里的hastNext在判断是否越界,next方法用于返回当前访问到的元素,cursor就是一个变量来表示访问到了第几个元素
那思路就清晰啦,我来给你梳理一下:增强for循环就是迭代器遍历,想要对象可以进行迭代器遍历,就要相应的类实现Iterable接口,表示可迭代的,实现了这个接口就要重写iterator方法,这个方法是用于暴露到外界来获取迭代器对象的,所以我们肯定要有一个类来表示迭代器对象,在这里定义成内部类再合适不过啦,定义的内部类迭代器对象需要实现Iterator接口,重写两个函数来表示迭代器的具体实现逻辑。
这种实现方式将很多信息隐藏在底层,这里就要扯出迭代器模式的概念了,如下:
迭代器模式是一种行为型设计模式,它提供了一种统一的方式来访问集合对象中的元素,而不是暴露集合内部的表示方式。简单地说,就是将遍历集合的责任封装到一个单独的对象中,我们可以按照特定的方式访问集合中的元素。
那我们就可以自己给Student实现迭代器功能,比如说来访问Student类的对象的每一个属性的值如下图,我们让Student的iterator方法返回我们定义的一个实现了Iterator接口的内部类StudentIterator,为了不报错,需要重写hasNext和next两个方法
这里的思路很简单啦(代码健全性先暂不考虑,我们先简单实现逻辑,之后慢慢来盘哈),我们定义三个变量,elementArray用来表示外部类的每个属性,这里为数组类型,泛型为Field,这里的Field全类名为java.lang.reflect.Field,看到reflect你可能猜到,这里的elementArray是通过反射拿到的,这里采用反射来拿信息,就不用内外类交互了。arrayLength是属性数组的长度,count是指针,用来表示遍历到第几个元素了,然后再init代码块中初始化变量
这里注意一下,elementArray表示的是Student类的每个属性名,而不是值,为了接下来的讲解不会让某些点让大家感到疑惑,我这边展示一下反射拿到属性每个值的代码:
接下来我们实现next方法,上图中我们可以看到反射拿取值element.get(student),element我们已经有了,就在数组里,对象怎么拿到?别忘了Student类是返回了一个StudentIterator对象回去,那我们我可以利用构造函数传递呀,则hasNext实现如下两图: 

2.代码健全性——迭代器常见的两个Exception
1.NoSuchElementException
换句话就是数组越界了,有人疑惑了,不是?我hasNext判断了啊,而且next里指针每次就加一,这些代码符合迭代器模式,都在底层没暴露出去,外界修改不了指针的值呀,怎么会越界,你这种想法是建立在调用一次hasNext后只调用一次next,如下图代码:集合内只有5个元素,但调用了多次next
我们可以看到ArrayList源码中就在next中做了判断:
所以我们也做个判断,让我们的StudentIterator代码更加健全:
2.ConcurrentModificationException
从英文字面上理解就是在遍历过程中对集合进行了修改,当然这里所说的修改是指手动删除添加元素(Iterator其实在内部提供了一个remove方法让我们安全得删除元素),也就是改变集合的长度,写过迭代器的朋友肯定知道这个报错,让我们来看看ArrayList源码中在哪抛的这个错误
跟进如下图,我们这里是浅析就不分析每个变量,下面的代码就是在判断集合长度是否变化了,在这里你肯定很疑惑,为什么要做这个判断?
这个问题我之前也想了一会,我来给一种说法,看如下代码,假如遍历到的元素为5,就添加一个5到集合元素中去,我们知道,集合的底层实现其实就是个数组,假如我们添加元素是将元素添加到最后面,那么这个迭代遍历永远不会结束,假如我们是把元素添加到前面,那每次添加元素意味着数组要移位一次,假如数组很大,时间复杂度是不小的,所以我想这个错误是为了避免这些极端情况
三.后言
好啦,看到这我相信你已经能得心应手得实现一个迭代器啦,也懂了一部分集合源码,ArrayList的源码就不说啦,因为上面所有内容就算讲了一遍了,第二个错误的健全代码也不说啦,我希望你自己去看源码自己实现,也挺简单的,第一次开坑设计模式系列,看大家喜不喜欢这类小白文再考虑要不要实习期间花时间更新吧,有问题欢迎在评论区交流,我也是初学者,共勉
相关文章:
Java迭代器【设计模式之迭代器模式】
目录 一.前言 二.正文 1.我写的类为什么不能使用增强for(迭代器遍历) 2.代码健全性——迭代器常见的两个Exception 1.NoSuchElementException 2.ConcurrentModificationException 三.后言 一.前言 本篇面向对象主要为和我一样的小白,主要是对迭代器模式的浅…...
Eclipse IDE
创建新的Java项目和类 在 Eclipse IDE 中创建一个新的 Java 项目和 Java 类的步骤如下: 1. 创建新的 Java 项目 打开 Eclipse IDE。在菜单栏中,点击 File > New > Java Project。在弹出的对话框中,输入项目名称(例如&…...
【面试篇】多线程
基础概念 线程的生命周期有哪些状态?它们是如何转换的? 答案:线程的生命周期有以下六种状态: 新建(New):线程被创建但尚未启动,此时线程对象已被分配内存空间,相关属性已…...
MySQL表缺乏主键或唯一索引对主从复制的深度影响及解决方案
引言 在MySQL数据库设计中,主键(Primary Key)和唯一索引(Unique Index)不仅是数据完整性的基石,更是主从复制(Replication)可靠性的关键。然而,许多开发者或DBA因历史遗…...
计算机视觉算法实战——基于YOLOv8的自动驾驶障碍物实时感知系统
✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连✨ 引言:自动驾驶感知系统的关键挑战 自动驾驶技术正以前所未有的速度重塑交通出行方式ÿ…...
【boost搜索引擎】下
boost搜索引擎 1. 编写搜索引擎模块 Searcher2. 编写 http_server 模块3. 编写前端模块4. 添加日志5. 补充 去掉暂停词6. 项目扩展方向 1. 编写搜索引擎模块 Searcher 这一模块主要提供建立索引,以及收到用户的发起的http请求通过Get方法提交的搜索关键字ÿ…...
数据结构优化DP总结
单调栈:Codeforces Round 622 (Div. 2) C2. Skyscrapers (hard version) 简单来讲就是最后需要呈现出一个单峰数组,使得总高度最高。 最开始想到暴力枚举每一个元素都充当最高的“单峰”,但是这里的 n 过大,这样枚举肯定会TLE。 …...
[Linux系统编程]进程间通信—system V
进程间通信—system V 1. System V 共享内存(Shared Memory)1.1 共享内存的建立过程1.2 共享内存函数2. System V 消息队列(Message Queues)3. System V 信号量(Semaphores)4. 总结前言: 之前所提的管道通信是基于文件的,OS没有做过多的设计工作。 system V 进程间通信…...
Eigen库几何模块深度解析与实践指南
Eigen库几何模块深度解析与实践指南 a. Eigen几何模块概述 i. 几何模块的核心功能 在三维空间中,几何变换是描述物体位置和姿态变化的基础,其数学基础涵盖了线性代数中的矩阵运算等知识。Eigen库的几何模块为这些变换提供了高效且便捷的实现方式。 旋转、平移和缩放是三维…...
第十四届蓝桥杯大赛软件赛省赛C/C++ 大学 B 组(部分题解)
文章目录 前言日期统计题意: 冶炼金属题意: 岛屿个数题意: 子串简写题意: 整数删除题意: 总结 前言 一年一度的🏀杯马上就要开始了,为了取得更好的成绩,好名字写了下前年2023年蓝桥…...
C语言常见3种排序
主要是三种排序方法:冒泡排序、选择排序、插入排序。 文章目录 一、冒泡排序 1.代码: 2.工作原理: 3.具体过程: 二、选择排序 1.代码 2. 工作原理 3.具体过程: 三、插入排序 1.代码 2.工作原理 3.具体过程 总结 一、…...
分析sys高问题的方法总结
一、背景 sys高的问题往往属于底层同学更需要关注的问题,sys高的问题往往表现为几种情况,一种是瞬间的彪高,一种是持续的彪高。这篇博客里,我们总结一下常用的分析方法和分析工具的使用来排查这类sys高的问题。 二、通过mpstat配…...
智谱发布AI Agent“AutoGLM沉思”,开启AI“边想边干”新时代
近日,智谱正式推出全新AI Agent产品——AutoGLM沉思,标志着人工智能从“思考”迈向“执行”的关键突破。该智能体不仅具备深度研究能力,还能自主完成实际操作,真正实现“边想边干”的智能化应用。 在演示环节,智谱展示…...
使用Leaflet对的SpringBoot天地图路径规划可视化实践-以黄花机场到橘子洲景区为例
目录 前言 一、路径规划需求 1、需求背景 2、技术选型 3、功能简述 二、Leaflet前端可视化 1、内容布局 2、路线展示 3、转折路线展示 三、总结 前言 在当今数字化与智能化快速发展的时代,路径规划技术已经成为现代交通管理、旅游服务以及城市规划等领域的…...
【小兔鲜】day02 Pinia、项目起步、Layout
【小兔鲜】day02 Pinia、项目起步、Layout 1. Pinia2. 添加Pinia到Vue项目3. 案例:Pinia-counter基础使用3.1 Store 是什么?3.2 应该在什么时候使用 Store? 4. Pinia-getters和异步action4.1 getters4.2 action如何实现异步 1. Pinia Pinia 是 Vue 的专…...
PyTorch 激活函数
激活函数是神经网络中至关重要的组成部分,它们为网络引入了非线性特性,使得神经网络能够学习复杂模式。PyTorch 提供了多种常用的激活函数实现。 常用激活函数 1. ReLU (Rectified Linear Unit) 数学表达式: PyTorch实现: torch.nn.ReLU(inplaceFals…...
魔塔社区使用llamafactory微调AI阅卷试题系统
启动 LLaMA-Factory 1. 安装 LLaMA-Factory 执行安装指令 git clone --depth 1 https://github.com/hiyouga/LLaMA-Factory.git cd LLaMA-Factory pip install -e ".[torch,metrics]"解决依赖冲突 如果遇到依赖冲突,可使用以下命令安装,不…...
Java面试黄金宝典29
1. 什么是普通索引和唯一性索引 定义: 普通索引:是最基本的索引类型,它为数据表中的某一列或多列建立索引,以加快数据的查询速度。它不限制索引列的值重复,允许存在多个相同的值。唯一性索引:在普通索引的基…...
git `switch` 命令详解与实用示例
文章目录 git switch 命令详解与实用示例git switch vs git checkoutgit switch 用法1. 切换到已有分支2. 创建并切换到新分支3. 切换到上一个分支4. 切换到远程分支(自动创建本地分支并追踪远程)5. 放弃未提交的修改并切换分支 总结 git switch 命令详解…...
Oracle中文一二三四排序【失败】
原文地址: Oracle数据库如何对中文的一二三四五六七八九十数进行正序排列排序_中文数字排序-CSDN博客 自定义排序函数 -- 自定义中文映射阿拉伯数字函数 CREATE OR REPLACE FUNCTION P_ORDER_CHINESE_TO_ARABIC(V_NUM VARCHAR2) RETURN NUMBER IS BEGIN-- 根据…...
AWS S3 和 Lambda 使用
目录: AWS概述 EMR Serverless AWS VPC及其网络 关于AWS网络架构的思考 AWS S3 和 Lambda 使用 本文将通过一个实例来说明如何使用 AWS S3 和 Lambda。 使用场景:通过代码将文件上传到S3,该文件需要是公开访问的,并对上传的文件进…...
Mysql 在什么样的情况下会产生死锁?
在 MySQL 中,死锁是指两个或多个事务相互等待对方释放锁,导致所有相关事务无法继续执行的情况。死锁会影响数据库的并发性能,因此需要及时检测并处理。假设有两个事务 T1 和 T2: 事务 T1 首先锁定 表 A 的行 1。然后尝试锁定 表 B…...
符号秩检验
内容来源 非参数统计(第2版) 清华大学出版社 王星 褚挺进 编著 符号秩检验 在符号检验的基础上,增加了数据绝对值大小的信息 检验统计量 用一个简单的例子来说明 样本数据 X i , i 1 , ⋯ , 6 X_i,i1,\cdots,6 Xi,i1,⋯,6 如下 X …...
RainbowDash 的 Robot
H RainbowDash 的 Robot - 第七届校赛正式赛 —— 补题 题目大意: 给一个 n ∗ m n*m n∗m 的二维网格,在第 i i i 列中,前 a i a_i ai 单元格被阻断,无法通行,即 [ 1 , a i ] [1,a_i] [1,ai] 。 一个机器人正…...
yum repolist all全部禁用了 怎么办
文章目录 步骤思考解决yum仓库全部被禁用的问题步骤思考: 检查仓库状态:运行yum repolist all,查看所有仓库的启用状态。 被禁用的仓库会显示为disabled。 启用所有仓库:可以逐一启用,或者使用命令批量启用。 例如使用yum-config-manager --enable ‘*’,但需要注意是否有…...
SQL WHERE 与 HAVING
WHERE 和 HAVING 都是 SQL 中用于筛选数据的子句,但它们有重要的区别 WHERE 子句 在 分组前 过滤数据 作用于 原始数据行 不能使用聚合函数 执行效率通常比 HAVING 高 SELECT column1, column2 FROM table WHERE condition; HAVING 子句 在 分组后 过滤数据 …...
如何在 Unity3D 导入 Spine 动画
一、前言 《如何在 Unity3D 项目中导入 Spine 动画》,虽然在网上有很多这种文章,直接将问题交给 DeepSeek 也能得到具体的操作流程,但是照着他们提供的方法还是能遇到几个问题,比如: AI 回答没有提到 Unity 无法识别.…...
子网划分2
子网分配的问题,下列vlsm如何设置? 某公司申请了一个C类202.60.31.0的IP地址,要求设置三个子网,一个为100台主机,一个为50台主机,另一个为50台主机,用VLSM如何设置? 哪位高手指教一…...
C++的UDP连接解析域名地址错误
背景 使用c开发一个udp连接功能的脚本,可以接收发送数据,而且地址是经过内网穿透到外网的 经过 通常发送数据给目标地址,需要把目的地址结构化,要么使用inet_addr解析ip地址,要么使用inet_pton sockaddr_in target…...
23种设计模式中的观察者模式
定义了一种一对多的依赖关系,当一个对象的状态发生改变时,其所有依赖者都会收到通知并自动更新。 观察者模式是一种发布-订阅模式。它让发送通知的一方(被观察者)和接收通知的一方(观察者)能够解耦…...
