【集合框架】JDK1.8源码分析之HashMap & LinkedHashMap迭代器(三)

简介:   在遍历HashMap与LinkedHashMap时,我们通常都会使用到迭代器,而HashMap的迭代器与LinkedHashMap迭代器是如何工作的呢?下面我们来一起分析分析。

一、前言


  在遍历HashMap与LinkedHashMap时,我们通常都会使用到迭代器,而HashMap的迭代器与LinkedHashMap迭代器是如何工作的呢?下面我们来一起分析分析。


二、迭代器继承图


image.png


image.png


三、HashMap迭代器


  3.1 HashIterator


  HashIterator是一个抽象类,封装了迭代器内部工作的一些操作。

  HashIterator类属性


abstract class HashIterator {
    // 下一个结点
    Node<K,V> next;        // next entry to return
    // 当前结点
    Node<K,V> current;     // current entry
    // 期望的修改次数
    int expectedModCount;  // for fast-fail
    // 当前桶索引
    int index;             // current slot
}


说明:其中expectedModCount属性主要用于在遍历HashMap同时,程序对其结构是否进行了修改。若遍历同时修改了,则会抛出异常。


  HashIterator构造函数 


HashIterator() {
        // 成员变量赋值
        expectedModCount = modCount;
        Node<K,V>[] t = table;
        current = next = null;
        index = 0;
        // table不为空并且大小大于0
        if (t != null && size > 0) { // advance to first entry
            // 找到table数组中第一个存在的结点,即找到第一个具有元素的桶
            do {} while (index < t.length && (next = t[index++]) == null);
        }
    }


说明:next将表示第一个非空桶中的第一个结点,index将表示下一个桶。


  HashIterator核心函数分析


  1. hasNext函数


// 是否存在下一个结点
public final boolean hasNext() {
    return next != null; 
}

2. nextNode函数 


final Node<K,V> nextNode() {
    // 记录next结点
    Node<K,V> e = next;
    // 若在遍历时对HashMap进行结构性的修改则会抛出异常
    if (modCount != expectedModCount)
        throw new ConcurrentModificationException();
    // 下一个结点为空,抛出异常
    if (e == null)
        throw new NoSuchElementException();
    // 如果下一个结点为空,并且table表不为空;表示桶中所有结点已经遍历完,需寻找下一个不为空的桶
    if ((next = (current = e).next) == null && (t = table) != null) {
        // 找到下一个不为空的桶
        do {} while (index < t.length && (next = t[index++]) == null);
    }
    return e;
}

说明:nextNode函数屏蔽掉了桶的不同所带来的差异,就好像所有元素在同一个桶中,依次进行遍历。


  3. remove函数


public final void remove() {
    Node<K,V> p = current;
    // 当前结点为空,抛出异常
    if (p == null)
        throw new IllegalStateException();
    // 若在遍历时对HashMap进行结构性的修改则会抛出异常
    if (modCount != expectedModCount)
        throw new ConcurrentModificationException();
    // 当前结点为空
    current = null;
    K key = p.key;
    // 移除结点
    removeNode(hash(key), key, null, false, false);
    // 赋最新值
    expectedModCount = modCount;
}

3.2 KeyIterator


  KeyIterator类是键迭代器,继承自HashIterator,实现了Iterator接口,可以对HashMap中的键进行遍历。


  类定义 

final class KeyIterator extends HashIterator
    implements Iterator<K> {
    public final K next() { return nextNode().key; }
}

3.3 ValueIterator


  ValueIterator类是值迭代器,继承自HashIterator,实现了Iterator接口,与KeyIterator类似,对值进行遍历。  


final class ValueIterator extends HashIterator
    implements Iterator<V> {
    public final V next() { return nextNode().value; }

3.4 EntryIterator


  EntryIterator类是结点迭代器,继承自HashIterator,实现了Iterator接口,与KeyIterator、ValueIterator类似,对结点进行遍历。 


final class ValueIterator extends HashIterator
    implements Iterator<V> {
    public final V next() { return nextNode().value; }
}

四、LinkedHashMap迭代器


  4.1 LinkedHashIterator


  LinkedHashIterator是LinkedHashMap的迭代器,为抽象类,用于对LinkedHashMap进行迭代。 


  LinkedHashIterator类属性


abstract class LinkedHashIterator {
    // 下一个结点
    LinkedHashMap.Entry<K,V> next;
    // 当前结点
    LinkedHashMap.Entry<K,V> current;
    // 期望的修改次数
    int expectedModCount;
}

 LinkedHashIterator构造函数  


LinkedHashIterator() {
    // next赋值为头结点
    next = head;
    // 赋值修改次数
    expectedModCount = modCount;
    // 当前结点赋值为空
    current = null;
}

 LinkedHashIterator核心函数


  hasNext函数


// 是否存在下一个结点
public final boolean hasNext() {
    return next != null;
}


nextNode函数 


final LinkedHashMap.Entry<K,V> nextNode() {
    LinkedHashMap.Entry<K,V> e = next;
    // 检查是否存在结构性修改
    if (modCount != expectedModCount)
        throw new ConcurrentModificationException();
    // 当前结点是否为空
    if (e == null)
        throw new NoSuchElementException();
    // 赋值当前节点
    current = e;
    // 赋值下一个结点
    next = e.after;
    return e;
}


说明:由于所有的结点构成双链表结构,所以nextNode函数也很好理解,直接取得下一个结点即可。


public final void remove() {
    // 保存当前结点
    Node<K,V> p = current;
    if (p == null)
        throw new IllegalStateException();
    if (modCount != expectedModCount)
        throw new ConcurrentModificationException();
    current = null;
    K key = p.key;
    // 移除结点
    removeNode(hash(key), key, null, false, false);
    // 更新最新修改数
    expectedModCount = modCount;
}


4.2 LinkedKeyIterator


  LinkedHashMap的键迭代器,继承自LinkedHashIterator,实现了Iterator接口,对LinkedHashMap中的键进行迭代。 


final class LinkedKeyIterator extends LinkedHashIterator
    implements Iterator<K> {
    public final K next() { return nextNode().getKey(); }
}

4.3 LinkedValueIterator

  LinkedHashMap的值迭代器,继承自LinkedHashIterator,实现了Iterator接口,对LinkedHashMap中的值进行迭代。


final class LinkedValueIterator extends LinkedHashIterator
    implements Iterator<V> {
    public final V next() { return nextNode().value; }

4.4 LinkedEntryIterator


  LinkedHashMap的结点迭代器,继承自LinkedHashIterator,实现了Iterator接口,对LinkedHashMap中的结点进行迭代。 


final class LinkedEntryIterator extends LinkedHashIterator
    implements Iterator<Map.Entry<K,V>> {
    public final Map.Entry<K,V> next() { return nextNode(); }
}


五、总结


  HashMap迭代器与LinkedHashMap迭代器有很多相似的地方,对比进行学习效果更佳。迭代器要屏蔽掉底层的细节,提供统一的接口供用户访问。HashMap与LinkedHashMap的迭代器源码分析就到此为止,还是很简单的,谢谢各位园友观看~

 

目录
相关文章
软件工程——软件开发阶段(概要设计、详细设计)
需求分析确定了系统的开发目标,下一步工作就是软件设计。软件设计可以进一步地 分为两个阶段:总体设计和详细设计。确定系统的具体 实现方案、给出软件的模块结构、编写各个文档
|
存储 C语言
函数指针数组:更高效的代码实现方式——指针进阶(二)
函数指针数组:更高效的代码实现方式——指针进阶(二)
119 0
|
安全
HTTP请求错误:”基础连接已关闭,发送时发生错误”
本文讲解HTTP请求错误:”基础连接已关闭,发送时发生错误”的解决方法。
611 0
|
存储 编解码 Ubuntu
音视频linux环境安装ffmpeg
音视频linux环境安装ffmpeg
372 0
|
机器学习/深度学习 数据安全/隐私保护 计算机视觉
深度学习在图像识别中的应用及其挑战
本文将深入探讨深度学习技术在图像识别领域的应用,并分析其面临的主要挑战。我们将从深度学习的基本原理出发,逐步解析其在图像识别中的具体应用方式,包括卷积神经网络(CNN)的工作机制、数据集的重要性以及模型训练和优化的策略。同时,文章也将指出深度学习在图像识别方面遇到的挑战,如过拟合问题、计算资源的需求、数据偏见与隐私保护等,并提供可能的解决方案。通过引用最新的研究成果和数据分析,本文旨在为读者提供一个关于深度学习在图像识别领域应用的全面视角。
78 0
|
XML 存储 边缘计算
Excelize 发布 2.7.1 版本,Go 语言 Excel 文档基础库
Excelize 是 Go 语言编写的用于操作 Office Excel 文档基础库,2023年4月10日,社区正式发布了 2.7.1 版本,该版本包含了多项新增功能、错误修复和兼容性提升优化。
262 3
Excelize 发布 2.7.1 版本,Go 语言 Excel 文档基础库
|
弹性计算 大数据 测试技术
2023年5月阿里云服务器ECS租用优惠价格表
2023年5月阿里云服务器ECS租用优惠价格表,CPU内存配置可选2核2G、2核4G、2核8G、2核16G、4核4G、4核8G、4核16G、4核32G、8核8G、8核16G、8核32G、8核64G等配置,云服务器包括轻量应用服务器和云服务器ECS,ECS实例可选通用算力型u1、计算型c7、通用型g7和内存型r7实例
172 0
2023年5月阿里云服务器ECS租用优惠价格表
|
前端开发
React组件化的思想
React组件化的思想
React组件化的思想
|
Web App开发 前端开发 JavaScript
《图解HTML》第一节 浏览器简介
它利用网页连接了我们与网络。它可以打开网络上的网页,供我们阅读,娱乐,工作等等......
223 0
《图解HTML》第一节 浏览器简介
|
应用服务中间件 Linux
阿里云网站备案和公安备案一次性成功(经验分享)
看着Wordpress博客越来越火,一直想玩玩。刚开始,不知道便宜的弹性web托管支不支持Wordpress博客建站,决定先尝试下。然后就购买了空间和域名。并且备案一次性通过。下面就和大家分享下备案经历。
4826 0