【集合框架】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的迭代器源码分析就到此为止,还是很简单的,谢谢各位园友观看~

 

目录
相关文章
|
29天前
|
存储 Java
【Java集合类面试七】、 JDK7和JDK8中的HashMap有什么区别?
JDK7中的HashMap使用数组加链表解决冲突,而JDK8增加了红黑树结构以优化链表过长时的性能,提高查找效率。
|
1月前
|
存储 缓存 安全
深度剖析Java HashMap:源码分析、线程安全与最佳实践
深度剖析Java HashMap:源码分析、线程安全与最佳实践
|
1月前
|
存储 Java
HashMap与LinkedHashMap类型集合
【8月更文挑战第4天】`HashMap` 是基于哈希表实现的键值对存储结构,提供快速的查找、插入和删除操作,但不保证元素顺序。适用于不关心顺序且需高效操作的场景。 `LinkedHashMap` 继承自 `HashMap`,保持了元素的插入或访问顺序。适合需要按特定顺序遍历元素的应用,如按添加顺序显示购物车商品。其操作效率与 `HashMap` 相近。
|
3月前
|
存储 Java 测试技术
滚雪球学Java(66):Java之HashMap详解:深入剖析其底层实现与源码分析
【6月更文挑战第20天】🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
37 3
滚雪球学Java(66):Java之HashMap详解:深入剖析其底层实现与源码分析
|
3月前
|
存储 算法 安全
JDK源码分析-HashMap
JDK源码分析-HashMap
|
4月前
|
Java
Java jdk1.8 lambda 遍历集合的时候到底需不需判空
Java jdk1.8 lambda 遍历集合的时候到底需不需判空
|
4月前
|
Java API 数据处理
JDK 21中的序列集合:有序数据的新篇章
本文将深入探讨JDK 21中新增的序列集合(Sequenced Collections)的概念、特性以及其在现代软件开发中的应用。序列集合为有序数据的处理提供了更高效、更直观的方式,使得开发者能够更轻松地管理集合中元素的顺序。本文将通过示例代码展示序列集合的使用,并分析其与传统集合的区别与优势。
|
4月前
|
编解码 Java API
集合在JDK9中的新特性
集合在JDK9中的新特性
|
4月前
|
存储 算法
HashMap源码分析
HashMap源码分析
|
4月前
|
安全 Java 开发者
JDK 9:不可变集合类工厂方法的探索与实践
JDK 9引入了一系列新的不可变集合类工厂方法,这些方法为Java开发者提供了更加便捷和安全的方式来创建不可变集合。本文将深入探讨这些新方法的原理、优势以及如何在实际开发中应用它们。