在Java中遍历List时会用到Java提供的Iterator,Iterator十分好用,原因是:

迭代器是一种设计模式,它是一个对象,它可以遍历并选择序列中的对象,而开发人员不需要了解该序列的底层结构。迭代器通常被称为“轻量级”对象,因为创建它的代价小。

  Java中的Iterator功能比较简单,并且只能单向移动:

  (1) 使用方法iterator()要求容器返回一个Iterator。第一次调用Iterator的next()方法时,它返回序列的第一个元素。注意:iterator()方法是java.lang.Iterable接口,被Collection继承。

  (2) 使用next()获得序列中的下一个元素。

  (3) 使用hasNext()检查序列中是否还有元素。

  (4) 使用remove()将迭代器新返回的元素删除。

只要看看下面这个例子就一清二楚了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import java.util.*;
public class Muster {
 
    public static void main(String[] args) {
        ArrayList list = new ArrayList();
        list.add("a");
        list.add("b");
        list.add("c");
        Iterator it = list.iterator();
        while(it.hasNext()){
            String str = (String) it.next();
            System.out.println(str);
        }
    }
}

运行结果:

a
b
c

可以看到,Iterator可以不用管底层数据具体是怎样存储的,都能够通过next()遍历整个List。

但是,具体是怎么实现的呢?背后机制究竟如何呢?

这里我们来看看Java里AbstractList实现Iterator的源代码:

1.public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> { // List接口实现了Collection<E>, Iterable<E>
2
3.    protected AbstractList() { 
4.    } 
5.   
6.    ... 
7
8.    public Iterator<E> iterator() { 
9.    return new Itr();  // 这里返回一个迭代器
10.    } 
11
12.    private class Itr implements Iterator<E> {  // 内部类Itr实现迭代器
13.      
14.    int cursor = 0
15.    int lastRet = -1
16.    int expectedModCount = modCount; 
17
18.    public boolean hasNext() {  // 实现hasNext方法
19.            return cursor != size(); 
20.    } 
21
22.    public E next() {  // 实现next方法
23.            checkForComodification(); 
24.        try
25.        E next = get(cursor); 
26.        lastRet = cursor++; 
27.        return next; 
28.        } catch (IndexOutOfBoundsException e) { 
29.        checkForComodification(); 
30.        throw new NoSuchElementException(); 
31.        } 
32.    } 
33
34.    public void remove() {  // 实现remove方法
35.        if (lastRet == -1
36.        throw new IllegalStateException(); 
37.            checkForComodification(); 
38
39.        try
40.        AbstractList.this.remove(lastRet); 
41.        if (lastRet < cursor) 
42.            cursor--; 
43.        lastRet = -1
44.        expectedModCount = modCount; 
45.        } catch (IndexOutOfBoundsException e) { 
46.        throw new ConcurrentModificationException(); 
47.        } 
48.    } 
49
50.    final void checkForComodification() { 
51.        if (modCount != expectedModCount) 
52.        throw new ConcurrentModificationException(); 
53.    } 
54.    } 
55.}

可以看到,实现next()是通过get(cursor),然后cursor++,通过这样实现遍历。

这部分代码不难看懂,唯一难懂的是remove操作里涉及到的expectedModCount = modCount;

在网上查到说这是集合迭代中的一种“快速失败”机制,这种机制提供迭代过程中集合的安全性。

从源代码里可以看到增删操作都会使modCount++,通过和expectedModCount的对比,迭代器可以快速的知道迭代过程中是否存在list.add()类似的操作,存在的话快速失败!
在第一个例子基础上添加一条语句:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import java.util.*;
public class Muster {
 
    public static void main(String[] args) {
        ArrayList list = new ArrayList();
        list.add("a");
        list.add("b");
        list.add("c");
        Iterator it = list.iterator();
        while(it.hasNext()){
            String str = (String) it.next();
            System.out.println(str);
            list.add("s");        //添加一个add方法
        }
    }
}

运行结果:

a
Exception in thread "main" java.util.ConcurrentModificationException
  at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
  at java.util.ArrayList$Itr.next(Unknown Source)
  at com.hasse.Muster.main(Muster.java:11)

这就会抛出一个下面的异常,迭代终止。
 
关于modCount,API解释如下:
The number of times this list has been structurally modified. Structural modifications are those that change the size of the list, or otherwise perturb it in such a fashion that iterations in progress may yield incorrect results.
也就是说,modCount记录修改此列表的次数:包括改变列表的结构,改变列表的大小,打乱列表的顺序等使正在进行迭代产生错误的结果。
Tips:仅仅设置元素的值并不是结构的修改
我们知道的是ArrayList是线程不安全的,如果在使用迭代器的过程中有其他的线程修改了List就会抛出ConcurrentModificationException,这就是Fail-Fast机制。

Java中Iterator(迭代器)实现原理的更多相关文章

  1. Java中Iterator(迭代器)的用法及其背后机制的探究

    在Java中遍历List时会用到Java提供的Iterator,Iterator十分好用,原因是: 迭代器是一种设计模式,它是一个对象,它可以遍历并选择序列中的对象,而开发人员不需要了解该序列的底层结 ...

  2. 深入理解Java中的迭代器

    迭代器模式:就是提供一种方法对一个容器对象中的各个元素进行访问,而又不暴露该对象容器的内部细节. 概述 Java集合框架的集合类,我们有时候称之为容器.容器的种类有很多种,比如ArrayList.Li ...

  3. Java中Iterator类的详细介绍

    迭代器模式:就是提供一种方法对一个容器对象中的各个元素进行访问,而又不暴露该对象容器的内部细节. 概述 Java集合框架的集合类,我们有时候称之为容器.容器的种类有很多种,比如ArrayList.Li ...

  4. 从虚拟机指令执行的角度分析JAVA中多态的实现原理

    从虚拟机指令执行的角度分析JAVA中多态的实现原理 前几天突然被一个"家伙"问了几个问题,其中一个是:JAVA中的多态的实现原理是什么? 我一想,这肯定不是从语法的角度来阐释多态吧 ...

  5. 自己实现java中Iterator(迭代器功能)

    今天躺在床上忽然想到一个问题,迭代器的代码是如何实现的?于是乎不由自主的爬起来敲两行代码. List<String> list=new ArrayList<>(2); list ...

  6. 谈谈知识的融会贯通:以“java中的迭代器失效问题”为例

    提示 文中涉及知识点: Collection . Iterator Guava 中的 Lists.partition 方法 如果你对这两个知识点不了解,强烈建议阅读文中引用的参考文章. 场景一:以Ar ...

  7. 大杂烩 -- Java中Iterator的fast-fail分析

    基础大杂烩 -- 目录 Java中的Iterator非常方便地为所有的数据源提供了一个统一的数据读取(删除)的接口,但是新手通常在使用的时候容易报如下错误ConcurrentModificationE ...

  8. Java集合Iterator迭代器的实现

    一.迭代器概述 1.什么是迭代器? 在Java中,有很多的数据容器,对于这些的操作有很多的共性.Java采用了迭代器来为各种容器提供了公共的操作接口.这样使得对容器的遍历操作与其具体的底层实现相隔离, ...

  9. Java之iterator迭代器和iterable接口

    java.lang.Iterable java.util.Iterator Iterator是迭代器类,而Iterable是接口. 好多类都实现了Iterable接口,这样对象就可以调用iterato ...

随机推荐

  1. Python自定义排序

    比如自定义了一个class,并且实例化了这个类的很多个实例,并且组成一个数组.这个数组要排序,是通过这个class的某个字段来排序的.怎么排序呢? 有两种做法: 第一种是定义__cmp__( )方法: ...

  2. MVC AOP解决JsonResult返回json时间格式

    新建JsonNetResult类:JsonResult public class JsonNetResult: JsonResult { public JsonNetResult() { Settin ...

  3. C# 操作windows服务[启动、停止、卸载、安装]

    主要宗旨:不已命令形式操作windows服务 static void Main(string[] args) { var path = @"E:\开发辅助项目\WCF\WCF.Test\WC ...

  4. Vue报错:Uncaught TypeError: Cannot assign to read only property’exports‘ of object’#<Object>‘的解决方法

    发现问题 运行一下以前的一个Vue+webpack的 vue仿新闻网站  小项目,报错 由于自己vue学习不深入,老是这个报错,找了好久(确切的说是整整一下午^...^)才找到原因 -v- Uncau ...

  5. [SDOI2018]原题识别

    题解: ..感觉挺烦得 而且我都没有注意到树随机这件事情.. 就写个30分的莫队.. #include <bits/stdc++.h> using namespace std; #defi ...

  6. 【UOJ244】【UER #7】短路

    题解: 感觉贪心水平有所提高.. 首先比较显然的事情是我们可以枚举最深进行到哪一层 我们会发现,当且仅当该层是最小值才会使用决策, 并且是从该层的左上,走到右下 另外中间步骤就是(好难描述啊)一个单调 ...

  7. Android动画模式

    在Android中,有两种动画模式:Tween Animation(渐变动画)和Frame Animation(帧动画).渐变动画是通过对场景里的对象不断做图像变换(平移.缩放.旋转等)来产生动画效果 ...

  8. python辅助sql手工注入猜解数据库案例分析

    发现存在sql注入漏洞 简单一点可以直接用sqlmap工具暴库 但是如果想深入理解sql注入的原理,可以尝试手工注入,配合python脚本实现手工猜解数据库 首先hachbar开启 获取cms登录后的 ...

  9. RocketMQ 启动停止命令

    1.rocketmq的启动   进入rocketMQ解压目录下的bin文件夹 启动namesrv服务:nohup sh bin/mqnamesrv &  日志目录:{rocketMQ解压目录} ...

  10. P1182 数列分段`Section II` P1316 丢瓶盖 二分答案

    题目描述 对于给定的一个长度为N的正整数数列A-iA−i,现要将其分成M(M≤N)M(M≤N)段,并要求每段连续,且每段和的最大值最小. 关于最大值最小: 例如一数列4 2 4 5 142451要分成 ...