HashMap底层梳理

一、Hash函数

(1)概念

hash函数就是把一个任意长度的输入映射成固定长度的输出。

(2)hash冲突

① 概念

hash函数也会存在问题,有可能两个val值经过hash算法后,得到相同的hash值,这就是hash冲突(碰撞问题)。

② 解决办法

HashMap是主要通过数组+链表来解决hash冲突的,当发生冲突了,对象将会储存在链表的下一个节点中(第3种)。 HashMap在每个链表节点中储存键值对对象。
1、 开放定址法:
所谓的开放定址法就是一旦发生了冲突,就去寻找下一个空的散列地址,只要散列表足够大,空的散列地址总能找到,并将记录存入 。
2、再哈希法:
再哈希法又叫双哈希法,有多个不同的Hash函数,当发生冲突时,使用第二个,第三个,….,等哈希函数
计算地址,直到无冲突。虽然不易发生聚集,但是增加了计算时间;
3、链地址法:
链地址法的基本思想是:每个哈希表节点都有一个next指针,多个哈希表节点可以用next指针构成一个单向链表,被分配到同一个索引上的多个节点可以用这个单向 链表连接起来。
4、建立公共溢出区:
这种方法的基本思想是:将哈希表分为基本表和溢出表两部分,凡是和基本表发生冲突的元素,一律填入溢出表。
在这里插入图片描述

(3)好的hash算法应该考虑哪些点?

(1)hash算法效率得搞,要做到长的文本也能高效计算出hash值;
(2)hash值不能逆推出原文;
(3)两次输入,只要有一点不同,也得保证hash值不同;
(4)尽量分散,散列。

二、HashMap

(1)存储数据的结构:

基于hash表,JDK1.8中,hash表存储采用数组+链表+红黑树实现。(链表或数组)
每个数据单元都是一个node结构,里头有key、value、next 和hash,next字段就是发生hash冲突时,当前bucket桶位中的node与冲突node连成一个链表要用的字段。
——hash表是一种以键值对存储数据的结构,链式哈希表是一组链表组成的,每个链表称为一个“桶”,将所有元素通过散列的方式放到不同的桶中。
在这里插入图片描述

① hash表

  • 创建HashMap时,散列表数组的初始长度为16;
  • 散列表不是new出HashMap时就创建的,散列表是懒加载机制,只有第一次put数据时,它才创建。
  • 默认的负载因子及其用处:默认是0.75,作用是计算hash表扩容阈,默认是16*0.75=12,所以我们往HashMap中put12个值时,它就会自动扩容。

总结HashMap数组扩容(即resize)

  • 当hashmap中的元素越来越多的时候,碰撞的几率也就越来越高(因为数组的长度是固定的),所以为了提高查询的效率,就要对hashmap的数组进行扩容。
  • 当数组元素个数大于160.75时,会进行扩容,扩容为原来的2倍,216=32。(但是是原数组的数据转移到新数组中,需要计算其位置并复制,这会消耗性能)

② 链表转红黑树

  • 链表长度达到8,且当前hash表的数组长度达到64时,链表就会转为红黑树(否则就算到了8,hash表也只是会继续扩容,直到扩容至64)。
  • 相对于链表,红黑树结构可以大大减少查询时间(log N,会自平衡,减少层数,从而减少磁盘IO)。
  • (当链表长度小的时候,其遍历速度足够快,但是链表长了以后,转为树才行O(log N)。)

(2)HashMap的put工作原理

HashMap在put方法中,它使用hashCode()和equals()方法。当我们通过传递key-value对调用put方法的时候,HashMap使用Key hashCode()和哈希算法来找出存储key-value对的索引

如果索引处为空,则直接将value插入到对应的数组中;否则,判断是否是红黑树,若是,则在红黑树中插入,否则遍历链表进行插入,若长度大于8,则将链表转为红黑树,转成功之后再插入。

(3)HashMap的get工作原理

用key进行hash算法运算,得到hashcode,根据hashcode找到索引。定位到具体的桶。先判断是否为链表,不是就根据hashCode是否相等来返回值,为链表则遍历,知道hashCode相等再返回值。否则返回null

(4)HashMap为什么线程不安全?

Hash表扩容,如果两个及以上线程同时地遇到Hash表大小达到12的倍数时,就很可能会出现将oldTable转移到newTable的过程中遇到的问题,从而导致最终的hash表的值存储异常。

具体:当多个线程同时检测到总数量超过阈值时,就会同时调用resize方法,各自生成新数组并rehash后赋给map底层的数组table,最后只有一个线程生成的新数组被赋给table变量,其它的线程均丢失。
而且当某些线程已经完成赋值,而其他线程刚开始的时候,就会用已经被赋值的table作为原始数组,这样也会出问题。

三、红黑树的写入操作

TreeNode结构包括:指向父节点的parent指针、指向左右节点的left和right指针,以及颜色。
(1)找到插入节点的父结点
红黑树满足二叉搜索树的所有排序特性,寻找父节点操作与其一致,

持续更新。。。。。。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值