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

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

HashMap put 方法执行的时候,用的是 equals 方法判断当前 key 是否与表中存在的 key 相同。


我们这里没有重写 equals 方法,因此这里返回了 false。


所以,如果我们 hashCode 和 equals 方法都没有重写,那么就会出现下面示意图的情况:


image.png


如果,我们重写了 hashCode,没有重写 equals 方法,那么就会出现下面示意图的情况:


image.png


总之一句话:在 HashMap 中,如果用对象做 key,那么一定要重写对象的 hashCode 方法和 equals 方法。否则,不仅不能达到预期的效果,而且有可能导致内存溢出。


比如上面的示例,我们放到循环中去,启动参数我们加上 -Xmx10m,运行结果如下:


image.png


因为每一次都是 new 出来的 student 对象,hashCode 都不尽相同,所以会不停的触发扩容的操作,最终在 resize 的方法抛出了 OOM 异常。


奇怪的知识又增加了


写这篇文章的时候我翻了一下《Java 编程思想(第 4 版)》一书。


奇怪的知识又增加了两个。


第一个是在这本书里面,对于 HashMap 里面放对象的示例是这样的:


image.png


Groundhog:土拨鼠、旱獭。


Prediction:预言、预测、预告。


考虑一个天气预报系统,将土拨鼠和预报联系起来。


这 TM 是个什么读不懂的神仙需求?


image.png


幸好 why 哥学识渊博,闭上眼睛,去我的知识仓库里面搜索了一番。


原来是这么一回事。


在美国的宾西法尼亚州,每年的 2 月 2 日,是土拨鼠日。


根据民间的说法,如果土拨鼠在 2 月 2 号出洞时见到自己的影子,然后这个小东西就会回到洞里继续冬眠,表示春天还要六个星期才会到来。如果见不到影子,它就会出来觅食或者求偶,表示寒冬即将结束。


这就呼应上了,通过判断土拨鼠出洞的时候是否能看到影子,从而判断冬天是否结束。


这样,需求就说的通了。


image.png


第二个奇怪的知识是这样的。


关于 HashCode 方法,《Java编程思想(第4版)》里面是这样写的:


image.png


我一眼就发现了不对劲的地方:result=37*result+c。


前面我们才说了,基数应该是 31 才对呀?


image.png


作者说这个公式是从《Effective Java(第1版)》的书里面拿过来的。


这两本书都是 java 圣经啊,建议大家把梦幻联动打在留言区上。


《Effective Java(第1版)》太久远了,我这里只有第 2 版和第 3 版的实体书。


于是我在网上找了一圈第 1 版的电子书,终于找到了对应描述的地方:


image.png


可以看到,书里给出的公式确实是基于 37 去计算的。


翻了一下第三版,一样的地方,给出的公式是这样的:


image.png


而且,你去网上搜:String 的 hashCode 的计算方法。


都是在争论为什么是 31 。很少有人提到 37 这个数。


其实,我猜测,在早期的 JDK 版本中 String 的 hashCode 方法应该用的是 37 ,后来改为了 31 。


我想去下载最早的 JDK 版本去验证一下的,但是网上翻了个底朝天,没有找到合适的。

书里面为什么从 37 改到 31 呢?


作者是这样解释的,上面是第 1 版,下面是第 2 版:


image.png


用方框框起来的部分想要表达的东西是一模一样的,只是对象从 37 变成了 31 。


而为什么从 37 变成 31 ,作者在第二版里面解释了,也就是我用下划线标注的部分。


31 有个很好的特许,即用位移和减法来代替乘法,可以得到更好的性能:


31*i==(i<<5)-1。现代的虚拟机可以自动完成这种优化。


从 37 变成 31,一个简单的数字变化,就能带来性能的提升。


个中奥秘,很有意思,有兴趣的可以去查阅一下相关资料。


真是神奇的计算机世界。


好了,这次的文章就到这里啦。


才疏学浅,难免会有纰漏,如果你发现了错误的地方,可以在留言区提出来,我对其加以修改。


感谢您的阅读,我坚持原创,十分欢迎并感谢您的关注。


我是 why 哥,一个被代码耽误的文学创作者,不是大佬,但是喜欢分享,是一个又暖又有料的四川好男人。


欢迎关注我呀。


目录
相关文章
|
4天前
|
JavaScript 前端开发 Java
万万没想到,'this'关键字的真正威力
万万没想到,'this'关键字的真正威力
19 1
|
7月前
|
Cloud Native Go Python
面试前夜:最后准备的小贴士
面试前夜:最后准备的小贴士
31 0
|
10月前
|
缓存 Java 程序员
肝到头秃!百度强推并发编程笔记我爱了,原来这才叫并发
随着Java程序员的大幅增长,人们对Java程序员的要求也是越来越严苛。从现在Java岗的招聘需求来看,并发编程已经是我们Java程序员避不开的坎了! 编写正确的程序并不容易,而编写正确的并发程序就更难了。与顺序执行的程序相比,并发程序中显然更容易出现错误。而且并发性错误通常并不会以某种确定的方式显现出来。
|
安全 Java 编译器
学妹不懂Java泛型,非让我写一篇给她看看(有图为证)
笔者有个学妹就遇到了相同的境遇,学弟被泛型搞得头晕目眩,搞不懂泛型是个啥玩意。天天用的泛型也不知道啥玩意(她可能都不知道她有没有用泛型)。立图为证!当然,笔者深度还欠缺,如果错误还请指正!
112 0
学妹不懂Java泛型,非让我写一篇给她看看(有图为证)
|
存储 算法 Java
难倒无数程序员的ThreadLocal原理,就这样被美团大牛轻松讲透彻
什么是ThreadLocal? ThreadLocal 是一个本地线程副本变量工具类。主要用于将私有线程和该线程存放的副本对象做一个映射,各个线程之间的变量互不干扰。 ThreadLocal怎么使用? ThreadLocl使用比较简单,主要有三个方法:get()、set()、remove()
171 0
难倒无数程序员的ThreadLocal原理,就这样被美团大牛轻松讲透彻
|
算法 Java
快来,我悄悄的给你说几个HashCode的破事。 (1)
快来,我悄悄的给你说几个HashCode的破事。 (1)
102 0
快来,我悄悄的给你说几个HashCode的破事。 (1)
|
Java 测试技术
快来,我悄悄的给你说几个HashCode的破事。 (3)
快来,我悄悄的给你说几个HashCode的破事。 (3)
72 0
快来,我悄悄的给你说几个HashCode的破事。 (3)
|
安全 Java
快来,我悄悄的给你说几个HashCode的破事。 (2)
快来,我悄悄的给你说几个HashCode的破事。 (2)
123 1
快来,我悄悄的给你说几个HashCode的破事。 (2)
|
测试技术
快来,我悄悄的给你说几个HashCode的破事。 (4)
快来,我悄悄的给你说几个HashCode的破事。 (4)
78 0
快来,我悄悄的给你说几个HashCode的破事。 (4)
|
存储 缓存 前端开发
表弟面试被虐,我教他缓存连招,借机蹭了波奈雪的茶
表弟面试被虐,我教他缓存连招,借机蹭了波奈雪的茶
表弟面试被虐,我教他缓存连招,借机蹭了波奈雪的茶