持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第 4 天,点击查看活动详情
1 Hash 是什么
Hash 是一种散列的摘要算法,通过计算可以将对象变换成固定长度的输出,即输出固定长度的散列值。如下图所示:
HashTest 类重写了 hashCode 方法,hashCode 方法需要计算每个属性的 hashCode 值,进行累加。identityHashCode 方法返回的是对象地址的hash值,不论是否重写 hashCode 方法都不会改变其值。
Hash 算法的使用非常广泛, 作为信息校验进行字符串的对比和校验,这个场景在 hashmap 中有相关的应用,字符串的对比可以先校验hash值然后再使用equals 对比,通过 hash 算法,可以将请求均匀的分配到应用服务器上,同样的,也可以保证同一个用户访问同一个服务器,同一个用户信息存储在同一个表中。
2 hash 冲突
在面试八股文中,hashcode 相等,对象值不一定相等,如果重写euqlas 方法就需要重写 hashcode 方法。当遇到hash 冲突时,处理的方法如下:
2.1 链地址法
链地址法是常用的方法,例如在hashmap 中,对于相同的hash 值,会使用链表进行链接。该种方法使用链表方式来处理冲突的,这种简单的方式使得存储结构清晰,查询时的稳定性高,但是在删除和修改节点时需要遍历链表进行处理,另外还需要处理扩容和缩容时产生的rehash 问题。
2.2 再 hash 方法
提供多个hash 函数,当第一个hash 函数计算出来的hash 值冲突后,使用第二个hash 函数进行计算,该方法减少了聚集的问题,但是增加了hash 的计算时间。
2.3 建立公共溢出区
设立公共冲突区域,用于存储冲突的元素,哈希表分为基本表和溢出表两部分,凡是和基本表发生冲突的元素,一律填入溢出表。
2.4 开放定址法
开放定址法,即当 p = hash(key) 出现冲突时,以p为基准,产生另一个地址p1,如果再有冲突则以此类推。 开放定址有线性探测、二次平方探测、随机探测等三种方式。ThreadLocal 中的 ThreadLocalMap 即采用线性探测的方式。
3 总结
在本文中,主要讲述了 hash 冲突是怎么回事儿,以及发生 hash 冲突时的解决方案,最常用的方案是解决方案就是使用链地址法,常用的使用案例就是 hashmap 了。