java迭代器cas,java提高篇(三十)-Iterator - Java 技术驿站-Java 技术驿站

迭代对于我们搞Java的来说绝对不陌生。我们常常使用JDK提供的迭代接口进行Java集合的迭代。

Iterator iterator = list.iterator();

while(iterator.hasNext()){

String string = iterator.next();

//do something

}

迭代其实我们可以简单地理解为遍历,是一个标准化遍历各类容器里面的所有对象的方法类,它是一个很典型的设计模式。Iterator模式是用于遍历集合类的标准访问方法。它可以把访问逻辑从不同类型的集合类中抽象出来,从而避免向客户端暴露集合的内部结构。 在没有迭代器时我们都是这么进行处理的。如下:

对于数组我们是使用下标来进行处理的:

int[] arrays = new int[10];

for(int i = 0 ; i < arrays.length ; i++){

int a = arrays[i];

//do something

}

对于ArrayList是这么处理的:

List list = new ArrayList();

for(int i = 0 ; i < list.size() ; i++){

String string = list.get(i);

//do something

}

对于这两种方式,我们总是都事先知道集合的内部结构,访问代码和集合本身是紧密耦合的,无法将访问逻辑从集合类和客户端代码中分离出来。同时每一种集合对应一种遍历方法,客户端代码无法复用。 在实际应用中如何需要将上面将两个集合进行整合是相当麻烦的。所以为了解决以上问题,Iterator模式腾空出世,它总是用同一种逻辑来遍历集合。使得客户端自身不需要来维护集合的内部结构,所有的内部状态都由Iterator来维护。客户端从不直接和集合类打交道,它总是控制Iterator,向它发送"向前","向后","取当前元素"的命令,就可以间接遍历整个集合。

上面只是对Iterator模式进行简单的说明,下面我们看看Java中Iterator接口,看他是如何来进行实现的。

一、java.util.Iterator

在Java中Iterator为一个接口,它只提供了迭代了基本规则,在JDK中他是这样定义的:对 collection 进行迭代的迭代器。迭代器取代了 Java Collections Framework 中的 Enumeration。迭代器与枚举有两点不同:

1、迭代器允许调用者利用定义良好的语义在迭代期间从迭代器所指向的 collection 移除元素。

2、方法名称得到了改进。

其接口定义如下:

public interface Iterator {

boolean hasNext();

Object next();

void remove();

}

其中:

Object next():返回迭代器刚越过的元素的引用,返回值是Object,需要强制转换成自己需要的类型

boolean hasNext():判断容器内是否还有可供访问的元素

void remove():删除迭代器刚越过的元素

对于我们而言,我们只一般只需使用next()、hasNext()两个方法即可完成迭代。如下:

for(Iterator it = c.iterator(); it.hasNext(); ) {

Object o = it.next();

//do something

}

前面阐述了Iterator有一个很大的优点,就是我们不必知道集合的内部结果,集合的内部结构、状态由Iterator来维持,通过统一的方法hasNext()、next()来判断、获取下一个元素,至于具体的内部实现我们就不用关心了。但是作为一个合格的程序员我们非常有必要来弄清楚Iterator的实现。 下面就ArrayList的源码进行分析分析。

二、各个集合的Iterator的实现

下面就ArrayList的Iterator实现来分析,其实如果我们理解了ArrayList、Hashset、TreeSet的数据结构,内部实现,对于他们是如何实现Iterator也会胸有成竹的。因为ArrayList的内部实现采用数组,所以我们只需要记录相应位置的索引即可,其方法的实现比较简单。

2.1、ArrayList的Iterator实现

在ArrayList内部首先是定义一个内部类Itr,该内部类实现Iterator接口,如下:

private class Itr implements Iterator {

//do something

}

而ArrayList的iterator()方法实现:

public Iterator iterator() {

return new Itr();

}

所以通过使用ArrayList.iterator()方法返回的是Itr()内部类,所以现在我们需要关心的就是Itr()内部类的实现:

在Itr内部定义了三个int型的变量:cursor、lastRet、expectedModCount。其中cursor表示下一个元素的索引位置,lastRet表示上一个元素的索引位置

int cursor;

int lastRet = -1;

int expectedModCount = modCount;

从cursor、lastRet定义可以看出,lastRet一直比cursor少一所以hasNext()实现方法异常简单,只需要判断cursor和lastRet是否相等即可。

public boolean hasNext() {

return cursor != size;

}

对于next()实现其实也是比较简单的,只要返回cursor索引位置处的元素即可,然后修改cursor、lastRet即可,

public E next() {

checkForComodification();

int i = cursor; //记录索引位置

if (i >= size) //如果获取元素大于集合元素个数,则抛出异常

throw new NoSuchElementException();

Object[] elementData = ArrayList.this.elementData;

if (i >= elementData.length)

throw new ConcurrentModificationException();

cursor = i + 1; //cursor + 1

return (E) elementData[lastRet = i]; //lastRet + 1 且返回cursor处元素

}

checkForComodification()主要用来判断集合的修改次数是否合法,即用来判断遍历过程中集合是否被修改过。在java提高篇(二一)-----ArrayList中已经阐述了。modCount用于记录ArrayList集合的修改次数,初始化为0,,每当集合被修改一次(结构上面的修改,内部update不算),如add、remove等方法,modCount + 1,所以如果modCount不变,则表示集合内容没有被修改。该机制主要是用于实现ArrayList集合的快速失败机制,在Java的集合中,较大一部分集合是存在快速失败机制的,这里就不多说,后面会讲到。所以要保证在遍历过程中不出错误,我们就应该保证在遍历过程中不会对集合产生结构上的修改(当然remove方法除外),出现了异常错误,我们就应该认真检查程序是否出错而不是catch后不做处理。

final void checkForComodification() {

if (modCount != expectedModCount)

throw new ConcurrentModificationException();

}

对于remove()方法的是实现,它是调用ArrayList本身的remove()方法删除lastRet位置元素,然后修改modCount即可。

public void remove() {

if (lastRet < 0)

throw new IllegalStateException();

checkForComodification();

try {

ArrayList.this.remove(lastRet);

cursor = lastRet;

lastRet = -1;

expectedModCount = modCount;

} catch (IndexOutOfBoundsException ex) {

throw new ConcurrentModificationException();

}

}

这里就对ArrayList的Iterator实现讲解到这里,对于Hashset、TreeSet等集合的Iterator实现,各位如果感兴趣可以继续研究,个人认为在研究这些集合的源码之前,有必要对该集合的数据结构有清晰的认识,这样会达到事半功倍的效果!!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/529827.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mysqldb mysql config,安装mysqldb python界面时找不到mysql_config

mySQLdb是一个用于mysql的python界面&#xff0c;但它不是mysql本身。 显然mySQLdb需要命令“mysql_config”&#xff0c;所以你需要先安装。你能否确认你是否通过从shell运行“mysql”来安装mysql本身&#xff1f; 这应该给你一个“mysql&#xff1a;command not found”以外的…

kfcm算法matlab实现,KFCM算法分析

function [center, U, obj_fcn] KFCMClust(data, cluster_n, kernel_b,options)% FCMClust.m 采用模糊C均值对数据集data聚为cluster_n类%% 用法&#xff1a;% 1. [center,U,obj_fcn] KFCMClust(Data,N_cluster,kernel_b,options);% 2. [center,U,obj_fcn] KFCMClus…

matlab中的terminator模块,2.2 Ground 及 Terminator模块

课时&#xff1a;117节课时长&#xff1a;20.1小时课级&#xff1a;中级提高simulink是matlab中的一种可视化仿真工具&#xff0c; 是一种基于matlab的框图设计环境&#xff0c;是实现动态系统建模、仿真和分析的一个软件包&#xff0c;被广泛应用于线性系统、非线性系统、数字…

matlab 柯西黎曼方程,【判断题】柯西-黎曼方程成立是函数解析的必要条件.

参考答案如下判断【判断题】核糖体的沉降系数等于大小亚基沉降系数的总和。题柯【其它】We ______________________________________ (投入到各项校园课外活动中) on campus.西黎【单选题】起动机与蓄电池的连接线蓄电池与车架的搭铁线则采用( )。 (2.0分)曼方【简答题】作业选…

取整函数php,php取整函数三个例子

本节内容&#xff1a;php取整函数用法1&#xff0c;php取整函数 ceil -- 取最大整数float ceil ( float value )返回不小于 value 的下一个整数&#xff0c;value 如果有小数部分则进一位。ceil() 返回的类型仍然是 float&#xff0c;因为 float 值的范围通常比 integer 要大。…

python执行过程打印,如何在pytest运行过程中看到正常的打印输出?

乔在接受的答案中提出了一个评论 &#xff0c;他问道&#xff1a;有没有办法打印到控制台并捕获输出&#xff0c;以便它显示在junit报告中&#xff1f;在UNIX中&#xff0c;这通常被称为开球 。 理想情况下&#xff0c;开球而不是捕捉将是py.test默认。 非理想情况下&#xff0…

cfar恒虚警matlab实现,一种用于距离副瓣抑制的自适应恒虚警方法与流程

本发明涉及脉冲压缩雷达数字信号处理技术领域。背景技术&#xff1a;在传统的真空管体制雷达中&#xff0c;由于发射占空比受限&#xff0c;通过设计较低的雷达重复发射频率实现远距离的目标探测&#xff0c;但由于发射的是简单的脉冲调制波形&#xff0c;重复频率降低和脉宽加…

修改oracle数据连接数据库,如何修改oracle数据库的连接数

如何修改oracle数据库的连接数查询数据库当前进程的连接数&#xff1a;select count(*) from v$process;查看数据库当前会话的连接数&#xff1a;elect count(*) from v$session;查看数据库的并发连接数&#xff1a;select count(*) from v$session where statusACTIVE;查看当前…

oracle导出中文utf8乱码,ORACLE导入导出后发生中文乱码的原因及解决办法

从数据库服务器上使用exp导出时显示如下&#xff1a;[oraclekf15-1]:/users/oracle>$ exp username/passwdkf15-1/i1000 tablestable_name filetable_name_unix.dmp satisticsnone buffer1000000Export: Release 10.2.0.4.0 - Production on 星期四 8月 26 16:37:08 2010Cop…

基于matlab的图解粒度参数计算,基于MATLAB的图解粒度参数计算

摘要粒度特征是沉积物的基本特征之一。计算沉积物粒度参数的方法主要有矩法和图解法两种&#xff0c;其中图解法必须通过手工作图求累积曲线&#xff0c;是一项相当繁杂的劳动&#xff0c;不利于计算大量样品。文中提出的方法将图解求沉积物样品的累积曲线百分位数的过程转化为…

oracle判断数据出现交叉,Oracle!你必须要知道的Knowledge points(一)

一、入门oracle有四个用户&#xff0c;分别为sys、system、sysman和scott,其中sys是oracle权限最高的用户&#xff0c;类似于Linux系统的root&#xff0c;scott是示例用户&#xff0c;上课就以这个用户里的三张员工表empno、dept、salgrade作为示例来授课。启动服务1. 快捷键ct…

php上传中文图片,用PHP处理图片文件的上传

这篇文章主要介绍了关于用PHP处理图片文件的上传&#xff0c;有着一定的参考价值&#xff0c;现在分享给大家&#xff0c;有需要的朋友可以参考一下1.html文件form表单注意。enctype属性代码&#xff1a;<?php require(../../public/common/config.php);$sqlClass "s…

nodejs+php+aes加密解密,php,crypto_php与nodejs的加密数据互通,php,crypto,node.js - phpStudy...

php与nodejs的加密数据互通nodejs的加密解密代码示例如下&#xff1a;#!/usr/bin/env nodevar crypto require(crypto);//解密function decode(cryptkey, iv, secretdata) {vardecipher crypto.createDecipheriv(aes-256-cbc, cryptkey, iv),decoded decipher.update(secret…

360 php offer,审批终于通过了,从面试到拿到奇虎360的offer已经失…

审批终于通过了&#xff0c;从面试到拿到奇虎360的offer已经失业两周了( •͈ᴗ⁃͈)ᓂ- - -♡&#xfeff;小运营大太阳&#xff1a;沾沾喜气程序猿.南兰&#xff1a;沾沾喜气360员工&#xff1a;欢迎来到酒仙桥第一养老院美团点评员工&#xff1a;[害羞]沾沾喜气盗圣白展堂&a…

linux中的进程权限是,Linux中权限,进程,服务的简单操作

1.权限存在意义- rw-r-r-r-- 1 root root 216 May 12 2017 /mnt/rht[1] [2] [3] [4] [5] [6] [7] [8][1] 文件类型-普通文件d目录l软链接ssocketc文件权限[2] 文件权限rw-|r--|r--u g ouuserggroupoo…

linux 中断 进程,linux中断分上下部分原因

中断处理程序在处理中断时起到了关键作用&#xff0c;也是一个中断程序必不可少的部分。不过&#xff0c;现如今的中断处理流程都会分为两部分&#xff1a;上半部分(top half)和下半部分(bottom half)。为什么要将一个中断分为如此两部分&#xff1f;下面的几个经典原因可以很好…

linux 运行eclipse,解决Linux下Eclipse启动错误

下载Eclipse后一打开就报错&#xff1a;JVM terminated. Exit code-1-Xms40m-Xmx256m-XX:MaxPermSize256m-Djava.class.path/usr/local/eclipse/plugins/org.eclipse.equinox.launcher_1.0.201.R35x_v20090715.jar-os linux-ws gtk-arch x86-showsplash /usr/local/eclipse//pl…

linux家庭云服务器,linux服务器云(linux家用云服务器)

可以。注&#xff1a;云服务器有Linux版本&#xff0c;实际上就是Linux在本地环境放到了云上公网环境中&#xff0c;其它操作都是一样的。云主机是集群服务器开发出的虚拟的机器&#xff0c;所以&#xff0c;这个因素不用考虑就问题不大。需要linux系统直接在预装系统安装就可以…

linux13位时间戳,Kotlin 处理Linux时间戳

思路1. 获取时间可以采用的方式有直接获取系统时间System.currentTimeMillis()或者使用Calendar类获取时间2. 处理时间在使用Calendar时&#xff0c;可以直接由Calendar的set方法对于时间进行设置由于Calendar的时间格式并不是我们希望得到的Linux时间戳格式&#xff0c;所以我…

linux脚本done报错,linux – 如何在shell脚本中处理错误/异常?

下面是我在bash中执行的脚本.它工作正常.fileexist0for i in $( ls /data/read-only/clv/daily/Finished-HADOOP_EXPORT_&processDate#.done); domv /data/read-only/clv/daily/Finished-HADOOP_EXPORT_&processDate#.done /data/read-only/clv/daily/archieve-wip/fil…