快来,我悄悄的给你说几个HashCode的破事。 (1)

简介: 快来,我悄悄的给你说几个HashCode的破事。 (1)

Hash冲突是怎么回事


在这个文章正式开始之前,先几句话把这个问题说清楚了:我们常说的 Hash 冲突到底是怎么回事?


直接上个图片:


image.png


你说你看到这个图片的时候想到了什么东西?


有没有想到 HashMap 的数组加链表的结构?


对咯,我这里就是以 HashMap 为切入点,给大家讲一下 Hash 冲突。


接着我们看下面这张图:


image.png


假设现在我们有个值为 [why技术] 的 key,经过 Hash 算法后,计算出值为 1,那么含义就是这个值应该放到数组下标为 1 的地方。


但是如图所示,下标为 1 的地方已经挂了一个 eat 的值了。这个坑位已经被人占着了。


那么此时此刻,我们就把这种现象叫为 Hash 冲突。


HashMap 是怎么解决 Hash 冲突的呢?


链地址法,也叫做拉链法。


数组中出现 Hash 冲突了,这个时候链表的数据结构就派上用场了。


链表怎么用的呢?看图:


image.png


这样问题就被我们解决了。


其实 hash 冲突也就是这么一回事:不同的对象经过同一个 Hash 算法后得到了一样的 HashCode。


那么写到这里的时候我突然想到了一个面试题:


请问我上面的图是基于 JDK 什么版本的 HashMap 画的图?


为什么想到了这个面试题呢?


因为我画图的时候犹豫了大概 0.3 秒,往链表上挂的时候,我到底是使用头插法还是尾插法呢?


image.png


众所周知,JDK 7 中的 HashMap 是采用头插法的,即 [why技术] 在 [eat] 之前,JDK 8 中的 HashMap 采用的是尾插法。


这面试题怎么说呢,真的无聊。但是能怎么办呢,八股文该背还是得背。


面试嘛,背一背,不寒碜。


构建 HashCode 一样的 String


前面我们知道了,Hash 冲突的根本原因是不同的对象经过同一个 Hash 算法后得到了一样的 HashCode。


这句话乍一听:嗯,很有道理,就是这么一回事,没有问题。


比如我们常用的 HashMap ,绝大部分情况 key 都是 String 类型的。要出现 Hash 冲突,最少需要两个 HashCode 一样的 String 类。


那么我问你:怎么才能快速弄两个 HashCode 一样的 String 呢?


image.png


怎么样,有点懵逼了吧?


从很有道理,到有点懵逼只需要一个问题。


来,我带你分析一波。


我先问你:长度为 1 的两个不一样的 String,比如下面这样的代码,会不会有一样的 HashCode?


String a = "a";
String b = "b";


肯定是不会的,对吧。


如果你不知道的话,建议你去 ASCII 码里面找答案。


我们接着往下梳理,看看长度为 2 的 String 会不会出现一样的 HashCode?


要回答这个问题,我们要先看看 String 的 hashCode 计算方法,我这里以 JDK 8 为例:


image.png


我们假设这两个长度为 2 的 String,分别是 xy 和 ab 吧。


注意这里的 xy 和 ab 都是占位符,不是字符串。


类似于小学课本中一元二次方程中的未知数 x 和 y,我们需要带入到上面的 hashCode 方法中去计算。


hashCode 算法,最主要的就是其中的这个 for 循环。


image.png


h 初始情况下等于 0。


String 类型的底层结构是 char 数组,这个应该知道吧。


所以,value.length 是字符串的长度。val[] 就是这个 char 数组。


把 xy 带入到 for 循环中,这个 for 循环会循环 2 次。


第一次循环:h=0,val[0]=x,所以 h=31*0+x,即 h=x。


第二次循环:h=x,val[1]=y,所以 h=31*x+y。


所以,经过计算后, xy 的 hashCode 为 31*x+y。


同理可得,ab 的 hashCode 为 31*a+b。


由于我们想要构建 hashCode 一样的字符串,所以可以得到等式:


31x+y=31a+b


那么问题就来了:请问 x,y,a,b 分别是多少?


你算的出来吗?


你算的出来个锤子!黑板上的排列组合你不是舍不得解开,你就是解不开。


但是我可以解开,带大家看看这个题怎么搞。


数学课开始了。注意,我要变形了。


image.png

目录
相关文章
|
7月前
|
Cloud Native Go Python
面试前夜:最后准备的小贴士
面试前夜:最后准备的小贴士
29 0
|
存储 JSON JavaScript
听说你情人节没人陪,这不我来给你介绍对象啦
听说你情人节没人陪,这不我来给你介绍对象啦
185 0
听说你情人节没人陪,这不我来给你介绍对象啦
|
测试技术
快来,我悄悄的给你说几个HashCode的破事。 (4)
快来,我悄悄的给你说几个HashCode的破事。 (4)
76 0
快来,我悄悄的给你说几个HashCode的破事。 (4)
|
Java
快来,我悄悄的给你说几个HashCode的破事。 (5)
快来,我悄悄的给你说几个HashCode的破事。 (5)
88 0
快来,我悄悄的给你说几个HashCode的破事。 (5)
|
安全 Java
快来,我悄悄的给你说几个HashCode的破事。 (2)
快来,我悄悄的给你说几个HashCode的破事。 (2)
122 1
快来,我悄悄的给你说几个HashCode的破事。 (2)
|
Java 测试技术
快来,我悄悄的给你说几个HashCode的破事。 (3)
快来,我悄悄的给你说几个HashCode的破事。 (3)
69 0
快来,我悄悄的给你说几个HashCode的破事。 (3)
|
存储 缓存 前端开发
表弟面试被虐,我教他缓存连招,借机蹭了波奈雪的茶
表弟面试被虐,我教他缓存连招,借机蹭了波奈雪的茶
表弟面试被虐,我教他缓存连招,借机蹭了波奈雪的茶
|
SQL
开胃菜12
开胃菜12
85 0
开胃菜12
【日拱一卒进击大厂系列】ArrayList的面试陷阱别跳进去了
【日拱一卒进击大厂系列】ArrayList的面试陷阱别跳进去了
【日拱一卒进击大厂系列】ArrayList的面试陷阱别跳进去了
|
API
大佬也hashcode方法上翻船了,不小心秀了一把!
大佬也hashcode方法上翻船了,不小心秀了一把!
121 0