• 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是一个素数!

    所谓素数:

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

    在存储数据计算hash地址的时候,我们希望尽量减少有同样的hash地址,所谓“冲突”。如果使用相同hash地址的数据过多,那么这些数据所组成的hash链就更长,从而降低了查询效率!所以在选择系数的时候要选择尽量长(31 = 11111[2])的系数并且让乘法尽量不要溢出(如果选择大于11111的数,很容易溢出)的系数,因为如果计算出来的hash地址越大,所谓的“冲突”就越少,查找起来效率也会提高。

    31可以 由i*31== (i<<5)-1来表示,现在很多虚拟机里面都有做相关优化,使用31的原因可能是为了更好的分配hash地址,并且31只占用5bits!

    在java乘法中如果数字相乘过大会导致溢出的问题,从而导致数据的丢失.

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

    如i*31==(i<<5)-1  用二进制表示就是:
    1<<5  移位 位100000
    11111==100000-1 
  • 相关阅读:
    使用python写天气预告
    beef配合ettercap批量劫持内网的浏览器
    html布局
    python 使用paramiko模块上传本地文件到ssh
    mysql一些函数的记录
    python与ssh交互
    html笔记4
    html笔记3
    html笔记2
    html笔记1
  • 原文地址:https://www.cnblogs.com/345214483-qq/p/6472130.html
Copyright © 2020-2023  润新知