DK1.8源码分析之HashMap & LinkedHashMap迭代器(三)

来源:互联网 发布:caffe cudnn 编辑:程序博客网 时间:2024/06/06 17:09

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

一、前言

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

二、迭代器继承图

  

  

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

 

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 s7刷机有三星帐号id怎么办 做主播留不住人怎么办 直播间留不住人怎么办 淘宝直播间留不住人怎么办 干了一个月不发工资怎么办 16岁长白色头发怎么办 腾讯乘车码解约了怎么办 蓝洞棋牌客封号怎么办 草莓被蚂蚁吃了怎么办 脖子被种了草莓怎么办 2岁的宝宝说脏话怎么办 欠钱的人跑路了怎么办 美国非婚生子父亲不认怎么办 孕4个月肚子胀气怎么办 8个月孕妇感冒了怎么办 孕8个月感冒鼻塞怎么办 怀孕八个月感冒了怎么办 孕八个月咳嗽了怎么办 享物说同城自提怎么办 锤基意外怀孕怎么办 08 蛐蛐罐底翻砂了怎么办 剑网3中被盗号后怎么办 本人想离婚对方躲避怎么办 微信不能说语音怎么办 微信语音发不了怎么办 吃鸡语音用不了怎么办 要杀我的人见面怎么办 转晕了想吐怎么办 原地转圈头晕恶心想吐怎么办 孩子吃凉的呕吐头还晕怎么办 孩子转晕了想吐怎么办 转圈晕了想吐怎么办 我爸总是骂我妈怎么办 转圈转的想吐怎么办 大便干燥拉不出来怎么办 吹完头发很干燥怎么办 腿摔伤了结痂疼怎么办 蹭wifi被禁止后怎么办 电脑wifi给拉黑怎么办 电脑想用无线网怎么办 中路被对方打崩了怎么办