HashCode的秘密

看String源码HashCode的计算方式:
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value;

for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
若是String value="abcd"; 那么其计算结果为:
value[0]=a;
h=31*0+a;     --31*0+97
 =a;          --97
value[1]=b;
h=31*(31*0+a)+b;     --31*97+98
 =31*a+b;            --3007+98=3105
value[2]=31*(31*a+b)+c;    --96255+99
        =31*31*a+31*b+c;   --96354
value[3]=31*(31*31*a+31*b+c)+d       --31*96354+100
        =31*31*31*a+31*31*b+31*c+d   --2986974+100
h=31^(n-1)*value[0]+31^(n-2)*value[1]+31^(n-3)*value[2]+value[n-1];
 
 
进制转换的表示方法为:16进制的20表示成10进制就是:2×16¹+0×16º=32
那么HashCode的计算方式就是字符的ascii码 按照31进制的计算方式去计算。
-------------------------------------------------------------------------------------------
咱们会注意那个狗血的31这个系数为何老是在里面乘来乘去?为何不适用32或者其余数字?

你们都知道,计算机的乘法涉及到移位计算。当一个数乘以2时,就直接拿该数左移一位便可!选择31缘由是由于31是一个素数!java

所谓素数:优化

质数又称素数。指在一个大于1的天然数中,除了1和此整数自身外,无法被其余天然数整除的数。spa

在存储数据计算hash地址的时候,咱们但愿尽可能减小有一样的hash地址,所谓“冲突”。若是使用相同hash地址的数据过多,那么这些数据所组成的hash链就更长,从而下降了查询效率!因此在选择系数的时候要选择尽可能长(31 = 11111[2])的系数而且让乘法尽可能不要溢出(若是选择大于11111的数,很容易溢出)的系数,由于若是计算出来的hash地址越大,所谓的“冲突”就越少,查找起来效率也会提升。ci

31能够 由i*31== (i<<5)-1来表示,如今不少虚拟机里面都有作相关优化,使用31的缘由多是为了更好的分配hash地址,而且31只占用5bits!源码

在java乘法中若是数字相乘过大会致使溢出的问题,从而致使数据的丢失.虚拟机

而31则是素数(质数)并且不是很长的数字,最终它被选择为相乘的系数的缘由不过与此!hash

如i*31==(i<<5)-1  用二进制表示就是:
1<<5  移位 位100000
11111==100000-1 
相关文章
相关标签/搜索