下面是HashTable源码中的put方法:

注意上面注释标注的地方:

HashTable对于元素在哈希表中的坐标算法是:

  1. 将对象自身的哈希值key.hashCode()变为正数:hash & 0x7FFFFFFF
  2. 将上面得到的哈希值对表长取余,映射到哈希表中去。

HashMap中哈希算法比HashTable中的稍微复杂一点。总体可以分为两步:

一、重新计算key本身的哈希值

上面代码中,首先是一个三目运算符,判断key是不是等于null,等于null,则返回0作为哈希值。否则,运算(h=key.hashCode()) ^ (h >>> 16),将key的哈希值的高位与低位异或的结果作为低位,改为不变。

‘>>>’是无符号右移操作,高位补0.

为什么要这么做呢?下面这一点讲了过后我们就明白了

二、哈希坐标的计算

同样以put方法为例

从最后一行我们可以看出,HashMap的哈希坐标计算方法是: (n - 1) & hash,其中hash就是我们第一点讲的改进哈希码。

HashMap为什么要使用改进的hash码?

举例分析如下,假设key的原始哈希值是’1111 1111 1111 1111 1111 0000 1110 1010’


(ps:图片来自:https://blog.csdn.net/john_520/article/details/57415084)

我们注意到,在上面这种哈希表长度较小的情况下,哈希码只有低4位与表的长度进行了关联性计算。这会造成哈希码的不充分使用,从而更容易引起哈希冲突。为了充分利用哈希码的高位,HashMap通过(h=key.hashCode())
^ (h >>> 16)运算,将高位与低位异或,使得即使在表长较小的情况下,高位也能参与计算,使得冲突的概率减小了。

HashMap为什么要使用 (n - 1)
& hash ,而不是HashTable中求模的方式来计算哈希坐标呢?

我在Stack Overflow上找到了一个解答:

意思是说:“规范的解决方法是将哈希值与表长取模,而这个方式((n - 1) & hash
武汉英语学校充分利用了HashMap的表长是2的整数次幂的事实,使用效率较高的位与运算(取模的高度优化)来替代昂贵的取模运算。”

实际上这两种方式的实质是一样的,它只是利用了这样一个事实:在n是2的幂的情况下,(n - 1) & hash 等同于 hash%h。

在n是2的幂的情况下,为什么 (n - 1) & hash等同于
hash%h?

我们以10为例,演示如下:

可以看到,两种方式的计算结果是相同的(这不是巧合),这实际上是一个数学规律。

HashMap是怎么使得表长始终为2的整数次幂的?

在源码中有这样一个方法:

这个方法的作用如注释所说,是求大于cap的最小2的整数次幂。在用户指定的初始容量不是2的幂时,HashMap会调用该方法将其变得符合要求。此后,每次扩容时是这样的:

直接使用oldCap<<1来将容量扩大为原来的2倍,即乘以21

  1. 对数学规律的恰当应用可以优化代码的运行效率
  2. 位运算在JDK中运用的十分广泛,如上面讲解的使用位“与”运算替代求模。这种替代的内在原因是位运算比数学运算快很多。优化都在细节处。

我对JDK源码的阅读和中文注释都已经同步到Github,欢迎英语阅读困难户前往查看:)
链接是:https://github.com/Dodozhou/JDK,喜欢的话别忘了star哦。

HashMap与HashTable的哈希算法——JDK1.9源码阅读总结的更多相关文章

  1. 13 HashTable抽象哈希表类——Live555源码阅读(一)基本组件类

    这是Live555源码阅读的第一部分,包括了时间类,延时队列类,处理程序描述类,哈希表类这四个大类. 本文由乌合之众 lym瞎编,欢迎转载 http://www.cnblogs.com/oloroso ...

  2. JDK1.8源码阅读笔记(1)Object类

    JDK1.8源码阅读笔记(1)Object类 ​ Object 类属于 java.lang 包,此包下的所有类在使⽤时⽆需⼿动导⼊,系统会在程序编译期间⾃动 导⼊.Object 类是所有类的基类,当⼀ ...

  3. JDK1.8源码阅读系列之三:Vector

    本篇随笔主要描述的是我阅读 Vector 源码期间的对于 Vector 的一些实现上的个人理解,用于个人备忘,有不对的地方,请指出- 先来看一下 Vector 的继承图: 可以看出,Vector 的直 ...

  4. JDK1.8源码阅读笔记(2) AtomicInteger AtomicLong AtomicBoolean原子类

    JDK1.8源码阅读笔记(2) AtomicInteger AtomicLong AtomicBoolean原子类 Unsafe Java中无法直接操作一块内存区域,不能像C++中那样可以自己申请内存 ...

  5. JDK1.8源码阅读系列之四:HashMap (原创)

    本篇随笔主要描述的是我阅读 HashMap 源码期间的对于 HashMap 的一些实现上的个人理解,用于个人备忘,有不对的地方,请指出- 接下来会从以下几个方面介绍 HashMap 源码相关知识: 1 ...

  6. JDK1.7源码阅读tools包之------ArrayList,LinkedList,HashMap,TreeMap

    1.HashMap 特点:基于哈希表的 Map 接口的实现.此实现提供所有可选的映射操作,并允许使用 null 值和 null 键.(除了非同步和允许使用 null 之外,HashMap 类与 Has ...

  7. JDK1.8源码阅读系列之一:ArrayList

    本篇随笔主要描述的是我阅读 ArrayList 源码期间的对于 ArrayList 的一些实现上的个人理解,有不对的地方,请指出- 先来看一下 ArrayList 的继承图: 由图可以看出,Array ...

  8. JDK1.8源码阅读系列之二:LinkedList

    本篇随笔主要描述的是我阅读 LinkedList 源码期间的对于 LinkedList 的一些实现上的个人理解,有不对的地方,请指出- 先来看一下 LinkedList 的继承图: 由于 Abstra ...

  9. jdk1.8源码阅读

    一.java.lang java的基础类 1.object 所有类的爸爸 registerNatives() Class<?> getClass():返回运行时的类 int hashCod ...

随机推荐

  1. 【Unity Shader】---CG标准函数库

    1.CG标准函数库 和C的标准函数库类似,CG也提供了一系列的内建函数库,这些函数用于计算数学上的通用计算或算法(如纹理映射).例如:求取入射光线的反射光线用Reflect函数,求折射光线用Refla ...

  2. 深度探索区块链/基于Gossip的P2P数据分发(4)

    一.概述 背书节点模拟执行签名的结果会经过排序服务(Ording service)广播给所有的节点. 它提供的是一种原子广播服务(Atomic Broadcast),即在逻辑上所有节点接收到的消息顺序 ...

  3. 解决django项目无法连接远程mysql的问题

    我们都知道django项目可以通过修改settings.py文件中的DATABASES这个对象,使用不同的数据库. 如图所示,我们想连接远程的mysql,修改settings.py的配置 然后我们在终 ...

  4. Java数据结构之链表(Linked List)

    1.链表(Linked List)介绍 链表是有序的列表,但是它在内存存储结构如下: 2.特点: 链表是以节点的方式来存储,是链式存储 每个节点包含 data 域, next 域:指向下一个节点. 链 ...

  5. <每日一题> Day1:CodeForces.1140D.MinimumTriangulation(思维题)

    题目链接 参考代码: #include <iostream> using namespace std; int main() { ; int n; cin >> n; ; i ...

  6. Java:CAS(乐观锁)

    本文讲解CAS机制,主要是因为最近准备面试题,发现这个问题在面试中出现的频率非常的高,因此把自己学习过程中的一些理解记录下来,希望能对大家也有帮助. 什么是悲观锁.乐观锁?在java语言里,总有一些名 ...

  7. VS2015+QT环境配置后,Lauch Qt Designer打开失败,无法打开*.ui文件

    最近在VS2015上配置QT时出现了这个问题,遂百度其解决方法,解决之后记录下来.第一步: 在[解决方案资源管理器]中,右击你的 xxx.ui文件,选择[打开方式],此时列表中默认值是[ Qt des ...

  8. vue css中scoped

    1.什么是scoped vue组件中,在style标签中有一个属性,叫做scoped.当此标签拥有scoped属性的时候,该组件下的css样式只适用于本组件,而不会影响全局组件.这其实也相当于样式的模 ...

  9. python基础面试题:(1)

    1.以下用C语言开发的Python解释器是( ) A:python是Java语言开发的Python解析器,B:PyPy是使用Python语言开发的Python解析,C:IronPython是.net平 ...

  10. 你真的了解iOS的深浅拷贝吗?

    最近在简书看到了一篇关于iOS深浅拷贝的博客,下面做一下学习总结: 非集合类对象的copy和mutableCopy 非集合类对象指NSString.NSNumber.NSMutableString等对 ...