hashMap 全面解析

面试问到 hashmap 数据结构及源码实现

本篇全为文字,烦躁的可以直接看加粗部分

hashmap 其实是 数组加链表的实现方式,数组中每个值都是一个链表的头节点
初始化构造 hashmap 时,大家一般都是 new HashMap<>() 不传参数的,其实还有一个构造方法,有四个参数,分别是: 数组大小, key value 扩容因子
默认下,数组大小为 16 扩容因子为 0.75
另外,遍历 hashmap 的时候用到 Map.Entry, 其实这个 entry 就是 key value 在hashmap 底层的实现,换个表述就是 entry 组成了 map

先大体说一下, hashmap 根据 key 的值,算出一个小于数组大小的数 (我管它叫hashresult), 然后塞到这个数组中,如果两个 key 算出的值一样 (科学家叫它hash冲突) ,那就往链表里加,加到链表的头结点上(头插法),为什么是头插法,因为写 hashmap 的人认为新加的数据被查找的概率大.

put操作

其实 put (key,value) 很复杂,先计算出 key 的 hash 值,用一个算法,大体就像 MD5
加密一样,根据 key 得出一个固定长度的 hash 码, 源码中计算是用
hash码 & 数组长度-1 =hashresult
(这个hashresult是我随便起的.哈哈哈) 因为所计算出来的值要放到数组里.所以不能大于数组最大长度,故采用 & 数组长度 -1 的方式,
至于为啥是&操作,明明%也可以,因为 % 太特么慢了啊,这个不用 % 的操作就被科学家称作优化. 但是聪明的孩子发现了,有 BUG ,如果数组长度减1之后的二进制中有0,& 完了之后肯定是0,也就是说,0所在的那列已经打出 GG 了啊,是的,没错.本应该 GG 的 RNG, 哦不,&的优化算法告诉裁判,我还可以抢救一下,再加一段代码保证数组减一最终结果都是1就行了,而只有2的幂减1后的二进制才会都是0,

综上所述hashmap的长度都是2的幂

(程序猿管这种边开发边打补丁的骚操作叫敏捷开发,然后代码越来越多, BUG 越来越多…)好了不管程序猿了,既然保证了是偶数,就一切 OK了,然后讲到哪来?卧槽,才讲第一步.
第一步就是根据 key(姓氏) 确定你的祖宗是谁. (数组中的位置),value 相当于《你的名字》
好,接下来讲第二步,算完的结果决定了你要去哪个数组下的链表,如果老大的坑已经有人了,那好吧我去当老二.老二也也有人当了,那老子当老三… (这个认亲的过程,被称作hash碰撞的拉链法)
行了,祖宗也认了亲也认了,族谱中就能确认你是王二麻子的三舅子的小姑父的二表姐了.

扩容:

再然后是人口的扩张,社会的发展,族里人越来越多.链表越来越长.找一个人需要很久,怎么办! 好,将族谱扩大2倍,为什么是2倍呢.因为要保证长度是2的幂啊,那为什么不是4倍呢? 小明,滚出去! 好,什么时候算是族人超过临界值了呢,就是上面说的 扩容因子 (默认0.75) * 数组最大长度 (默认16)
就是默认情况下,超过最大的四分之三时 进行扩容操作,将容量扩大为原来的二倍.
然后最大长度变了,就得重新计算所有的 entry 的 hashresult 了,公式是 : hash 码 & 数组长度-1 = hashresult 然后再一个一个重新进入新容器.

总结:扩容

扩容就是 容量扩大二倍,带来的副作用就是 需要将所有的 entry 都计算一遍 放入新容器中,相当于建一个二倍容量的 hashmap ,然后再把所有的 entry 放进去.想想都及其耗时.

get操作

get 操作反过来一样的,根据 key 算出你祖宗是谁,然后根据 value 找出你在哪.比如: key= 富 value=铁柱,那么,会根据 key 算出你是老富家的(在数组的第几个位置),然后根据 value 去找链表中 equals 铁柱 的.然后就找出富铁柱这个人了.

先写到这,如果有没写到的,欢迎留言. 另:此为JDK 1.7 的数据结构,如果是1.8 ,用的更高端了,是红黑树.但是原理都差不多.

最后上一个我的笔记图.字秀的飞起,看图说话.这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值