关于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()函数中调用了HashIteratornextEntry()方法。所以,重点就变成了分析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()的实现的更多相关文章

  1. 透过byte数组简单分析Java序列化、Kryo、ProtoBuf序列化

    序列化在高性能网络编程.分布式系统开发中是举足轻重的之前有用过Java序列化.ProtocolBuffer等,在这篇文章这里中简单分析序列化后的byte数组观察各种序列化的差异与性能,这里主要分析Ja ...

  2. 简单分析Java中审批业务流程业务原理

  3. java基础---->hashMap的简单分析(一)

    HashMap是一种十分常用的数据结构对象,可以保存键值对.它在项目中用的比较多,今天我们就来学习一下关于它的知识. HashMap的简单使用 一.hashMap的put和get方法 Map<S ...

  4. Java源码分析:关于 HashMap 1.8 的重大更新(转载)

    http://blog.csdn.net/carson_ho/article/details/79373134 前言 HashMap 在 Java 和 Android 开发中非常常见 而HashMap ...

  5. 【Java】HashMap源码分析——常用方法详解

    上一篇介绍了HashMap的基本概念,这一篇着重介绍HasHMap中的一些常用方法:put()get()**resize()** 首先介绍resize()这个方法,在我看来这是HashMap中一个非常 ...

  6. 【Java】HashMap源码分析——基本概念

    在JDK1.8后,对HashMap源码进行了更改,引入了红黑树.在这之前,HashMap实际上就是就是数组+链表的结构,由于HashMap是一张哈希表,其会产生哈希冲突,为了解决哈希冲突,HashMa ...

  7. java基础---->hashSet的简单分析(一)

    对于HashSet而言,它是基于HashMap实现的,底层采用HashMap来保存元素的.今天我们就简单的分析一下它的实现.人生,总会有不期而遇的温暖,和生生不息的希望. HashSet的简单分析 一 ...

  8. Java动态替换InetAddress中DNS的做法简单分析1

    在java.net包描述中, 简要说明了一些关键的接口. 其中负责networking identifiers的是Addresses. 这个类的具体实现类是InetAddress, 底层封装了Inet ...

  9. java 中 “文件” 和 “流” 的简单分析

    java 中 FIle 和 流的简单分析 File类 简单File 常用方法 创建一个File 对象,检验文件是否存在,若不存在就创建,然后对File的类的这部分操作进行演示,如文件的名称.大小等 / ...

随机推荐

  1. java 解析汉字拼音

    pinyin4j的使用很方便,一般转换只需要使用PinyinHelper类的静态工具方法即可:    String[] pinyin = PinyinHelper.toHanyuPinyinStrin ...

  2. spring集成quartz scheduler

    创建项目 有两种创建quart配置作业 1.使用MethodInvokingJobDetailFactoryBean  Quartz Scheduler 配置作业(MethodInvokingJobD ...

  3. Android最佳性能实践(一)——合理管理内存

    有不少朋友都问过我,怎样才能写出高性能的应用程序,如何避免程序出现OOM,或者当程序内存占用过高的时候该怎么样去排查.确实,一个优秀的应用程序,不仅仅要功能完成得好,性能问题也应该处理得恰到好处.为此 ...

  4. jquery mobile 学习总结

    <!doctype html><html lang="zh-CN"><head> <meta charset="UTF-8&qu ...

  5. a++累加

    <!DOCTYPE html><html lang="zh-CN"><head> <meta charset="UTF-8&qu ...

  6. overflow:auto/hidden的应用

    一.自适应两栏布局 <!DOCTYPE html><html lang="zh-CN"><head> <meta charset=&quo ...

  7. 转:如何学习SQL(第四部分:DBMS扩展功能与SQL高级话题)

    转自:http://blog.163.com/mig3719@126/blog/static/285720652010950102575/ 9. DBMS提供的扩展功能 掌握了基本的关系模型原理和DB ...

  8. Nemo Documents – 给文件添加标签 以日历的形式将文件呈现出来,很像 Outlook,你可以根据年、月、日来查看不同类型的文档

    Nemo Documents – 给文件添加标签   scavin(Google+) on 2012.03.28. Nemo Documents 是款文件组织管理工具(文档管理器),不是街道大妈胜似大 ...

  9. EL表达式 (详解)(转)

    EL表达式      1.EL简介 1)语法结构        ${expression} 2)[]与.运算符      EL 提供.和[]两种运算符来存取数据.      当要存取的属性名称中包含一 ...

  10. SSH2 架构常用注解

    1. @Repository 将 DAO 类声明为 Bean 2.@Component 是一个泛化的概念,仅仅表示一个组件 (Bean) ,可以作用在任何层次. 3.@Service 通常作用在业务层 ...