简单分析Java的HashMap.entrySet()的实现
关于Java的HashMap.entrySet()
,文档是这样描述的:这个方法返回一个Set,这个Set是HashMap的视图,对Map的操作会在Set上反映出来,反过来也是。原文是
Returns a Set view of the mappings contained in this map. The set is backed by the map, so changes to the map are reflected in the set, and vice-versa.
本文通过源码简单分析这一功能的实现。
首先要简单介绍一下HashMap的内部存储。我们知道,Map是用来存储key-value类型数据的,一个<k, v>对在Map的接口定义中被定义为Entry,HashMap内部实现了Entry
接口。HashMap内部维护一个Entry
数组。
transient Entry[] table;
当put一个新元素的时候,根据key的hash值计算出对应的数组下标。数组的每个元素是一个链表的头指针,用来存储具有相同下标的Entry。
Entry[] table
+---+
| 0 | -> entry_0_0 -> entry_0_1 -> null
+---+
| 1 | -> null
+---+
| |
...
|n-1| -> entry_n-1_0 -> null
+---+
entrySet()
方法返回的是一个特殊的Set,定义为HashMap的内部私有类
private final class EntrySet extends AbstractSet<Map.Entry<K,V>>
主要看一下这个Set的iterator()
方法。这个方法很简单,返回一个EntryIterator
类型的实例。EntryIterator
类型是泛型HashIterator<T>
的一个子类,这个类的内容很简单,唯一的代码是在next()
函数中调用了HashIterator
的nextEntry()
方法。所以,重点就变成了分析nextEntry()
方法。上述过程见下面的图示
HashMap
|- table <------------------------------------\
\+ entrySet() |iterates
| HashMap.HashIterator<T> |
|returns ^ \- nextEntry()
V - ^
HashMap.EntrySet | |
\- iterator() |extends |
| | |
| instantiats | |calls
\----------> HashMap.EntryIterator |
\- next() /
HashIterator
通过遍历table
数组,实现对HashMap的遍历。内部维护几个变量:index
记录当前在table
数组中的下标,current
用来记录当前在table[index]
这个链表中的位置,next
指向current的下一个元素。nextEntry()
的完整代码如下:
final Entry<K,V> nextEntry() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
Entry<K,V> e = next;
if (e == null)
throw new NoSuchElementException();
if ((next = e.next) == null) {
Entry[] t = table;
while (index < t.length && (next = t[index++]) == null)
;
}
current = e;
return e;
}
第一个if
用来判断在多线程的情况下是否出现并发错误,这里暂时不讨论。如果next
不是null
,那么返回并更新next
。更新方法是第三个if
的内容:如果当前链表还没有结束,则简单的把next
向后移一个;否则在table
中查找下一个非空的slot。
总结一下,HashMap的entrySet()
方法返回一个特殊的Set,这个Set使用EntryIterator
遍历,而这个Iterator则直接操作于HashMap的内部存储结构table
上。通过这种方式实现了“视图”的功能。整个过程不需要任何辅助存储空间。
p.s. 从这一点也可以看出为什么entrySet()
是遍历HashMap最高效的方法,原因很简单,因为这种方式和HashMap内部的存储方式是一致的。
简单分析Java的HashMap.entrySet()的实现的更多相关文章
- 透过byte数组简单分析Java序列化、Kryo、ProtoBuf序列化
序列化在高性能网络编程.分布式系统开发中是举足轻重的之前有用过Java序列化.ProtocolBuffer等,在这篇文章这里中简单分析序列化后的byte数组观察各种序列化的差异与性能,这里主要分析Ja ...
- 简单分析Java中审批业务流程业务原理
- java基础---->hashMap的简单分析(一)
HashMap是一种十分常用的数据结构对象,可以保存键值对.它在项目中用的比较多,今天我们就来学习一下关于它的知识. HashMap的简单使用 一.hashMap的put和get方法 Map<S ...
- Java源码分析:关于 HashMap 1.8 的重大更新(转载)
http://blog.csdn.net/carson_ho/article/details/79373134 前言 HashMap 在 Java 和 Android 开发中非常常见 而HashMap ...
- 【Java】HashMap源码分析——常用方法详解
上一篇介绍了HashMap的基本概念,这一篇着重介绍HasHMap中的一些常用方法:put()get()**resize()** 首先介绍resize()这个方法,在我看来这是HashMap中一个非常 ...
- 【Java】HashMap源码分析——基本概念
在JDK1.8后,对HashMap源码进行了更改,引入了红黑树.在这之前,HashMap实际上就是就是数组+链表的结构,由于HashMap是一张哈希表,其会产生哈希冲突,为了解决哈希冲突,HashMa ...
- java基础---->hashSet的简单分析(一)
对于HashSet而言,它是基于HashMap实现的,底层采用HashMap来保存元素的.今天我们就简单的分析一下它的实现.人生,总会有不期而遇的温暖,和生生不息的希望. HashSet的简单分析 一 ...
- Java动态替换InetAddress中DNS的做法简单分析1
在java.net包描述中, 简要说明了一些关键的接口. 其中负责networking identifiers的是Addresses. 这个类的具体实现类是InetAddress, 底层封装了Inet ...
- java 中 “文件” 和 “流” 的简单分析
java 中 FIle 和 流的简单分析 File类 简单File 常用方法 创建一个File 对象,检验文件是否存在,若不存在就创建,然后对File的类的这部分操作进行演示,如文件的名称.大小等 / ...
随机推荐
- elcipse 安装svn插件 转载
1.下载最新的Eclipse,我的版本是3.7.2 indigo(Eclipse IDE for Java EE Developers)版 如果没有安装的请到这里下载安装:http://ecli ...
- adb_常用命令
1. adb push 电脑中的文件(包含路径) Android中的绝对路径 2. adb pull Android中的绝对路径文件 电脑中的绝对路径 3. adb install ??.ap ...
- tracert命令详解
一.windows.Linux系统下 tracert ip/网站域名 二.mac traceroute IP/域名 ---------2016-10-10 15:29:07-- source:[1]t ...
- php用curl调用接口方法,get和post两种方式
首先是客户端执行方法ApiModel.php: <?php /** * 模拟post进行url请求 * @param string $url * @param array $post_data ...
- Linux命令之乐--awk
1.脚本参数传值 #/bin/bash awk '"} {if(($1==a)) print $2;}' /etc/hosts 执行结果:
- JavaSE复习_6 枚举类
△单例类是指只有一个实例,而枚举类实际上就是有有限个实例的类,在类里已经把实例定义好了. △枚举类的三种创建形式: 1) enum Week { MON,TUE,WED;//枚举类有默认构造函数创建的 ...
- 货币金额的计算 - Java中的BigDecimal
在<Effective Java>这本书中也提到这个原则,float和double只能用来做科学计算或者是工程计算,在商业计算中我们要用 java.math.BigDecimal.,而且使 ...
- D3.js 选择元素和绑定数据/使用数据
选择元素和绑定数据是 D3 最基础的内容,本文将对其进行一个简单的介绍. 一.如何选择元素 在 D3 中,用于选择元素的函数有两个: d3.select():是选择所有指定元素的第一个 d3.sele ...
- D3.js 理解 Update、Enter、Exit
Update.Enter.Exit 是 D3 中三个非常重要的概念,它处理的是当选择集和数据的数量关系不确定的情况. 一.什么是 Update.Enter.Exit svg.selectAll(&qu ...
- shelve模块
#coding:utf-8 __author__ = 'similarface' #email:similarface@outlook.com ''' shelve模块: 映射容器 存储对象,被存储的 ...