【集合框架】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的迭代器源码分析就到此为止,还是很简单的,谢谢各位园友观看~
【集合框架】JDK1.8源码分析之HashMap & LinkedHashMap迭代器(三)的更多相关文章
- 【集合框架】JDK1.8源码分析之HashMap(一) 转载
[集合框架]JDK1.8源码分析之HashMap(一) 一.前言 在分析jdk1.8后的HashMap源码时,发现网上好多分析都是基于之前的jdk,而Java8的HashMap对之前做了较大的优化 ...
- 【集合框架】JDK1.8源码分析之HashMap(一)
一.前言 在分析jdk1.8后的HashMap源码时,发现网上好多分析都是基于之前的jdk,而Java8的HashMap对之前做了较大的优化,其中最重要的一个优化就是桶中的元素不再唯一按照链表组合,也 ...
- 【集合框架】JDK1.8源码分析之HashMap
一.前言 在分析jdk1.8后的HashMap源码时,发现网上好多分析都是基于之前的jdk,而Java8的HashMap对之前做了较大的优化,其中最重要的一个优化就是桶中的元素不再唯一按照链表组合,也 ...
- JDK1.8源码分析之HashMap(一) (转)
一.前言 在分析jdk1.8后的HashMap源码时,发现网上好多分析都是基于之前的jdk,而Java8的HashMap对之前做了较大的优化,其中最重要的一个优化就是桶中的元素不再唯一按照链表组合,也 ...
- JDK1.8源码分析之HashMap
一.前言 在分析jdk1.8后的HashMap源码时,发现网上好多分析都是基于之前的jdk,而Java8的HashMap对之前做了较大的优化,其中最重要的一个优化就是桶中的元素不再唯一按照链表组合,也 ...
- 【集合框架】JDK1.8源码分析HashSet && LinkedHashSet(八)
一.前言 分析完了List的两个主要类之后,我们来分析Set接口下的类,HashSet和LinkedHashSet,其实,在分析完HashMap与LinkedHashMap之后,再来分析HashSet ...
- 【集合框架】JDK1.8源码分析之ArrayList详解(一)
[集合框架]JDK1.8源码分析之ArrayList详解(一) 一. 从ArrayList字表面推测 ArrayList类的命名是由Array和List单词组合而成,Array的中文意思是数组,Lis ...
- 【集合框架】JDK1.8源码分析之Collections && Arrays(十)
一.前言 整个集合框架的常用类我们已经分析完成了,但是还有两个工具类我们还没有进行分析.可以说,这两个工具类对于我们操作集合时相当有用,下面进行分析. 二.Collections源码分析 2.1 类的 ...
- 集合之TreeSet(含JDK1.8源码分析)
一.前言 前面分析了Set接口下的hashSet和linkedHashSet,下面接着来看treeSet,treeSet的底层实现是基于treeMap的. 四个关注点在treeSet上的答案 二.tr ...
随机推荐
- .NET 4.5.1 预览版新特性
上个月的微软Build大会上宣布了.NET 4.5.1的推出,Heydarian的这个演讲题为".NET开发中的新内容",涵盖了.NET Framework中一些重要的新特性. H ...
- Linux服务器安装笔记 汇总
系统 Ubuntu笔记:http://www.cnblogs.com/newsea/p/4746967.html CentOs笔记:http://www.cnblogs.com/newsea/p/47 ...
- MySQL MVCC(多版本并发控制)
概述 为了提高并发MySQL加入了多版本并发控制,它把旧版本记录保存在了共享表空间(undolog),当事务提交之后将重做日志写入磁盘(前提innodb_flush_log_at_trx_commit ...
- C#之委托与事件
委托与事件 废话一堆:网上关于委托.事件的文章有很多,一千个哈姆雷特就有一千个莎士比亚,以下内容均是本人个人见解. 1. 委托 1.1 委托的使用 这一小章来学习一下怎么简单的使用委托,了解一些基本的 ...
- JavaScript面试时候的坑洼沟洄——数据类型
前些日子写了篇关于最近找工作的一些感受的博客 找工作的一些感悟--前端小菜的成长,没想到得到了很多园友的共鸣,得到了很多鼓励,也有园友希望我分享一些笔试.面试的经验.我觉得分享一些笔试题没太多价值,对 ...
- 说说Java程序和数据库交互的乱码解决
本文就本人遇到的问题进行讲解 1.通过jdbc直连方式,连接Mysql数据库,从程序向数据库中写入数据出现的乱码解决方案. 当通过程序向Student表中写入一条数据时,写入数据库的内容会产生乱码. ...
- Cookie与Session
再说Cookie与Session之前,先要了解一下http协议. 何为http协议: http协议即超文本传输协议,一种基于浏览器请求与服务器响应的协议,该协议主要的特点就是它是一种无状态的协议(只针 ...
- react-native环境搭建
目标平台 Android 开发平台 windows 开发环境安装建议:由于开发环境存在差异,建议参照react官网 或者react中文网 安装, react-native -- 在Windows下搭建 ...
- ClickOnce部署(1):一些发布方式
ClickOnce是什么玩意儿,这个问题嘛,在21世纪的互联网严重发达的时代,估计也没有必要大费奏章去介绍了,弄不好的话,还有抄袭之嫌.因此,有关ClickOnce的介绍,各位朋友可以直接查找MSDN ...
- 【转】WPF 单选的Checkbox
今天同事要在DataGrid里用单选的Checkbox,我感觉很多余,因为正常DataGrid就可以单选,为什么还要加一列Checkbox,但是人家要求再那里,我就告诉他,可以用RadioButton ...