String hashCode() 设计的道理

查到实现如下,那么为什么是乘31呢?这样有什么优点或者道理呢?
public int hashCode() {
int h = hash;
if (h == 0) {
int off = offset;
char val[] = val;
int len = count;
for (int i = 0; i < len; i++) {
h = 31*h + val[off++];
}
hash = h;
}
return h;
}

链接:https://www.zhihu.com/question/24381016/answer/112861010

说到hashCode()里的魔法数字,还是得搬Bloch在《Effective Java》里的原话来呀:之所以选择31,是因为它是个奇素数,如果乘数是偶数,并且乘法溢出的话,信息就会丢失,因为与2相乘等价于移位运算。使用素数的好处并不是很明显,但是习惯上都使用素数来计算散列结果。31有个很好的特性,就是用移位和减法来代替乘法,可以得到更好的性能:31*i==(i<<5)-i。现在的VM可以自动完成这种优化。B大的话,归纳起来就三点:一定要奇数。不能用偶数。素数不素数其实关系不大。用31是因为31=2^5-1。可以把乘法转换成开销更小的位移操作。提高效率。对于为什么用偶数信息会丢失,是因为对于二进制数来说,乘以2,就是一次左位移,在原数后面加个零。
比如有一个32位int:

0000001 00011010 00100111 11001001 *1024

1101000 10011111 00100100 00000000

乘以1024之后,等于向左位移10位,后面用零填满。最后原先第8位的1已经被移除去了,就是乘法溢出。原来数字的信息一点点被推出去,后面补上来的又都是零。信息越来越少。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值