美文网首页
基于jdk1.8的HashMap源码分析(二)

基于jdk1.8的HashMap源码分析(二)

作者: 小甲说 | 来源:发表于2018-10-21 00:54 被阅读0次

        再上次看了hashMap的put方法,了解了大概的流程,今天再来搞搞put中的hash(key) 方法和具体计算下标的方法

    1

        源码是这样的 

    static final int hash(Object key) {

    int h;

    return (key ==null) ?0 : (h = key.hashCode()) ^ (h >>>16);

    }

    相当于  h^h>>>16

    先来了解一下这几个运算符

        1.与运算符

            与运算符用符号“&”表示,其使用规律如下:

            两个操作数中位都为1,结果才为1,否则结果为0,

            例如 1111 & 1110  结果为 1110 

            此种运算中 得到0的概率是0.25 得到1的概率是0.75    

        2.非运算符

            非运算符用符号“|”表示,其使用规律如下:

            两个位只要有一个为1,那么结果就是1,否则就为0

            例如 1111 & 1110  结果为 1111

            此种运算中 得到0的概率是0.75 得到1的概率是0.25

        3.异或运算符

            异或运算符是用符号“^”表示的,其运算规律是:

            两个操作数的位中,相同则结果为0,不同则结果为1。

            例如 1111 & 1110  结果为 0001

            此种运算中 得到0和1的概率都是0.5 

            接下来看h>>>16 

            源码中有这样一个常量

            static final int DEFAULT_INITIAL_CAPACITY =1 <<4;// aka 16

            1 <<4代表 1*2的4次方

            >>>  则代表 无符号右移,忽略符号位,空位都以0补齐

            h>>>16 则代表右移16位 即当key的hashCode值小于2的16次方时 h>>>16都为0

            h^h>>>16 就是高16位和低16位的异或运算 保证hash散列的平均分布

    2.计算下标

        if ((p = tab[i = (n -1) & hash]) ==null)

            tab[i] = newNode(hash, key, value,null);

        tab[I =(n-1)&hash] 

        此处关注的重点在于为何hashMap的初始化长度是2的4次方 以及resize()每次都是扩容为原来长度的2倍

        (1)我们知道 偶数的二进制最后一位是0 奇数的二进制最后一位是1 ,当(n-1)和hash进行&运算的时候, hash的最后一位不确定, &运算只有当都为1 ,结果才为1,否则结果为0。那么,如果(n-1)是偶数 计算出来的值最后一位肯定为0 必然会导致我们只能使用数组长度的一半 导致资源的浪费,产生大量的hash冲突。而(n-1)为奇数 则会避免这个问题

        (2)还有一种说法是 当length为偶数时 可以用&代替%运算 效率高 

                这点我还没想明白 后面有时间再补充吧

               

    相关文章

      网友评论

          本文标题:基于jdk1.8的HashMap源码分析(二)

          本文链接:https://www.haomeiwen.com/subject/skwmzftx.html