hashCode方法里为什么选择数字31作为生成hashCode值的乘数


前提:

  偶然的机会看到了大神的一篇博客,介绍的是hashCode()方法里为什么要用31这个数字作为生成hashCode的乘数。hashCode我在比较自定义类时曾经用到过 - 由于java默认比较的是类的地址值,每个对象一定是不同的,所以重写了hashCode()和equals()方法
,这样就会先根据类里的属性生成hashCode,如果生成的hashCode值相同,则在使用equals()比较属性的值。两者都相同则认为这两个对象相等。当是就对hashCode的生成很好奇,自己看了下源码也是懵懵懂懂。这下终于可以搞清楚了,开森,感谢大佬!

  hashCode()方法的源码:

原因一:更少的乘积结果冲突

  31是质子数中一个“不大不小”的存在,如果你使用的是一个如2的较小质数,那么得出的乘积会在一个很小的范围,很容易造成哈希值的冲突。而如果选择一个100以上的质数,得出的哈希值会超出int的最大范围,这两种都不合适。而如果对超过 50,000 个英文单词(由两个不同版本的 Unix 字典合并而成)进行 hash code 运算,并使用常数 31, 33, 37, 39 和 41 作为乘子,每个常数算出的哈希值冲突数都小于7个(国外大神做的测试),那么这几个数就被作为生成hashCode值得备选乘数了。

原因二:31可以被JVM优化

  JVM里最有效的计算方式就是进行位运算了:

* 左移 << : 左边的最高位丢弃,右边补全0(把 << 左边的数据*2的移动次幂)。
* 右移 >> : 把>>左边的数据/2的移动次幂。
* 无符号右移 >>> : 无论最高位是0还是1,左边补齐0。   

       所以 : 31 * i = (i << 5) - i(左边  31*2=62,右边   2*2^5-2=62) - 两边相等,JVM就可以高效的进行计算啦。。。

  ps:以前家里人老说学号数理化,走遍全天下。貌似很有道理^_^

 

posted @ 2018-01-27 20:13  阿拉巴洞  阅读(6456)  评论(1编辑  收藏  举报