美文网首页java高级开发群青春校园开发技巧
每个人都能看懂的 HashMap 原理漫画

每个人都能看懂的 HashMap 原理漫画

作者: Java技术剑 | 来源:发表于2020-02-05 14:08 被阅读0次

果哥:一线公司小码农,一直走在求职的路上。

果妹:一线公司美女面试官,一直和小码农们苦苦纠缠。

面试现场

果妹你上次不是要问我 HashMap 原来来着吗?

对哦,我记得你上次已经大概说了 HashMap 的基本结构了

漫画:HashSet 和 TreeSet 的实现与原理

那我问你点细节吧,你上次提到了 Hash,那么如果我想自定义一个 Class 作为 key,那么应该注意什么呢?

第一次遇到这么奇怪的问题,我想想啊……

我觉得应该是注意重写 hashCode 和 equals 方法。以 put 方法为例,因为在 HashMap 内部 hash 的时候需要用到hashCode,以此来判断两个 Class 实例的 hash 是否一致。equals 是用来在 hash 碰撞以后追加链表的时候比对看是否相同以便更新。

恩,那既然你提到了 hash 用到了 hashCode 方法,你来解释一下 HashMap 里面的 hash 具体怎么实现的呢?

好的,这个我还专门研究过,打开 HashMap源码,从 put 说起吧。它最先调用的是 hash 函数,然后和当前的 n - 1 做与运算得到 bucket 的下标,关键代码如下:

(h = key.hashCode()) ^ (h >>> 16) // 338 行

tab[i = (n - 1) & hash]  // 692 行

具体逻辑,先是获取 key 的 hashCode,然后把 hashCode 低位位移 16 位后和之前的 hashCode 做亦或运算得到最终的 hash 值, bucket 数量是有限的,所以需要和 n -1 与运算得到最终的下标,这么说可能比较晦涩,我简单画一个图吧。以 key 是 “果汁简历” 为例,n 默认为 16,下图是把十进制转换为二进制进行计算。

String value = "果汁简历";

int hashCode = value.hashCode(); //817810155

int lowBit = hashCode >>> 16; //12478

int hash = hashCode ^ lowBit; //817822293

int index = (n - 1) & hash; //5

如图,可以清楚的了解到 hash 的全过程,最后一步 (n -1) & hash很好理解,就是为了把计算好的 hash 映射到所有的 bucket 槽位。那么 h ^ (h >>> 16) 是因为通常情况 bucket 的槽位很少,用于参与运算的只有 hashCode 低位,为了让高位也可以参与运算,尽可能的在不影响性能的情况下避免冲突,所以做了一下高位右移 16 位然后亦或运算。

接下来的流程就相对比较好理解了,获取到 index 以后没有碰撞直接放入 bucket,如果碰撞了就追加到链表尾部,JDK8以前是头部,JDK8是为了计算步长等于 8 的时候转换为红黑树,所以每次都是遍历链表插入到尾部。说到红黑树上次已经回答你漫画:HashSet 和 TreeSet 的实现与原理,最后如果 size 超过了 factor * capacity 就会 resize()。

恩,果哥你掌握的还不错嘛,那顺便和我说说你理解的 resize 吧?

resize 就是自动扩容,当 size 达到阈值以后会扩容到原来的 2 倍,关键代码 newCap = oldCap << 1。但是这里有一个非常巧妙的解决方法,因为扩容是扩充的 2 倍,n-1 转换为二进制也就是高位变成了1,那么根据(n - 1) & hash 计算,如果 hash 高位是 1 那么新的 index 位置就是 oldIndex + 16,如果hash 的高位 是 0 ,那么 index 的位置就是原来的 oldIndex 的位置,这样直接判断高位就可以了,省去了重新计算hash。

通过 HashMap 源码我们也可以清楚的看到,714-743 行:

恩恩,掌握的还不错嘛,对了,说了这么多 HashMap 终究不是线程安全的,那么怎么样把它变成线程安全的你知道吗?

我记得有一个工具方法,java.util.Collections#synchronizedMap(Map<K,V> map),这个方法通过 synchronized 关键字使得 map 的每一个操作都变成了同步,这样就可以做到线程安全了。

ConcurrentHashMap 有听过吗?是不是线程安全的呢?给我讲讲这个吧。

哎呀,这个我还不太清楚诶,要不然我回去研究下,明天找你再考考我?

觉得文章不错就给小老弟点个关注吧,更多内容陆续奉上。

最后,分享一份面试宝典《Java核心知识点整理.pdf》,覆盖了JVM、锁、高并发、反射、Spring原理、微服务、Zookeeper、数据库、数据结构等等。加入我的个人粉丝群(Java架构技术栈:644872653)获取免费领取方式。

相关文章

  • 每个人都能看懂的 HashMap 原理漫画

    果哥:一线公司小码农,一直走在求职的路上。 果妹:一线公司美女面试官,一直和小码农们苦苦纠缠。 面试现场 果妹你上...

  • HashMap面试题

    其实HashMap中的逻辑不算复杂,如果看懂了我之前对于HashMap中核心方法源码的分析这些问题应该都能回答上来...

  • JDK1.7 HashMap

    通俗易懂的解释 ↓漫画:什么是HashMap?漫画:高并发下的HashMap详细的解释 ↓HashMap深度分析...

  • Java-HashMap 精讲原理篇

    本文涉及HashMap的: HashMap的简单使用 HashMap的存储结构原理 HashMap的扩容方法原理 ...

  • 2020-04-03 Java HashMap的实现原理的文章

    HashMap的扩容机制---resize() HashMap底层实现原理 扩容机制 Java中HashMap的实现原理

  • Java HashMap源码简单解析(JDK 1.8)

    简单分析以下HashMap的原理,put和get方法的原理。 HashMap介绍 HashMap继承Map接口,可...

  • hashmap底层原理

    1、“你知道HashMap的工作原理吗?” “你知道HashMap的get()方法的工作原理吗?” HashMap...

  • HashMap

    HashMap 的实现原理 HashMap 是基于 hashing 原理,我们通过 put() 和 get() ...

  • Hash*的实现原理

    HashMap和Hashtable的区别 HashMap的实现原理 Hashtable的实现原理 LInkedHa...

  • 2020-08-10 Map接口

    一、Map类的实现结构 1.HashMap HashMap底层原理: HashMap底层原理 JDK8的更新: H...

网友评论

    本文标题:每个人都能看懂的 HashMap 原理漫画

    本文链接:https://www.haomeiwen.com/subject/unzjxhtx.html