• HashMap中hash(Object key)原理,为什么(hashcode >>> 16)。


    大家都知道(jdk1.8)HashMap中计算数组下标是HashMap的核心算法。小编今天在看HashMap源码中看到了hash(Object key)方法百思不得其解。小编问百度,查找相关博客,甚至连HashMap的关于hash(Object key)英文解释都看了。但是都只是说了为了尽量均匀,没有详细讲。小编今天为大家详细讲解一下这两个问题。

    HashMap中hash(Object key)的原理,为什么这样做?
    先看下hash(Object key)方法,详细大家基本都能看懂,但是知道这一步(h = key.hashCode()) ^ (h >>> 16)原因的人很少。

    static final int hash(Object key) {
    int h;
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }
    首先这个方法的返回值还是一个哈希值。为什么不直接返回key.hashCode()呢?还要与 (h >>> 16)异或。首先要了解以下知识点:

    必备知识点.:^ 运算  >>>运算  &运算。

    1. h >>> 16 是什么,有什么用?
    h是hashcode。h >>> 16是用来取出h的高16,(>>>是无符号右移)   如下展示:

    0000 0100 1011 0011 1101 1111 1110 0001

    >>> 16

    0000 0000 0000 0000 0000 0100 1011 0011
    2. 为什么 h = key.hashCode()) 与 (h >>> 16) 异或
    讲到这里还要看一个方法indexFor,在jdk1.7中有indexFor(int h, int length)方法。jdk1.8里没有,但原理没变。下面看下1.7源码

    1.8中用tab[(n - 1) & hash]代替但原理一样。

    static int indexFor(int h, int length) {
    return h & (length-1);
    }
    这个方法返回值就是数组下标。我们平时用map大多数情况下map里面的数据不是很多。这里与(length-1)相&,

    但由于绝大多数情况下length一般都小于2^16即小于65536。所以return h & (length-1);结果始终是h的低16位与(length-1)进行&运算。如下例子(hashcode为四字节)

    例如1:为了方便验证,假设length为8。HashMap的默认初始容量为16

    length = 8;  (length-1) = 7;转换二进制为111;

    假设一个key的 hashcode = 78897121 转换二进制:100101100111101111111100001,与(length-1)& 运算如下
       

    0000 0100 1011 0011 1101 1111 1110 0001

    &运算

    0000 0000 0000 0000 0000 0000 0000 0111

    = 0000 0000 0000 0000 0000 0000 0000 0001 (就是十进制1,所以下标为1)
    上述运算实质是:001 与 111 & 运算。也就是哈希值的低三位与length与运算。如果让哈希值的低三位更加随机,那么&结果就更加随机,如何让哈希值的低三位更加随机,那么就是让其与高位异或。

    补充知识:

    当length=8时    下标运算结果取决于哈希值的低三位

    当length=16时  下标运算结果取决于哈希值的低四位

    当length=32时  下标运算结果取决于哈希值的低五位

    当length=2的N次方, 下标运算结果取决于哈希值的低N位。

    3. 原因总结
    由于和(length-1)运算,length 绝大多数情况小于2的16次方。所以始终是hashcode 的低16位(甚至更低)参与运算。要是高16位也参与运算,会让得到的下标更加散列。

    所以这样高16位是用不到的,如何让高16也参与运算呢。所以才有hash(Object key)方法。让他的hashCode()和自己的高16位^运算。所以(h >>> 16)得到他的高16位与hashCode()进行^运算。

    4. 为什么用^而不用&和|
    因为&和|都会使得结果偏向0或者1 ,并不是均匀的概念,所以用^。

    这就是为什么有hash(Object key)的原因。


    ————————————————
    版权声明:本文为CSDN博主「杨涛的博客」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/qq_42034205/article/details/90384772

    如果有来生,要做一片树叶。 春天恋上枝,炎夏恋上水。 深秋恋上土,东来化作泥。 润物细无声,生生世世恋红尘。
  • 相关阅读:
    Json对象与Json字符串互转(4种转换方式)
    Web.config配置文件详解
    jQuery BlockUI Plugin Demo 6(Options)
    jQuery BlockUI Plugin Demo 5(Simple Modal Dialog Example)
    jQuery BlockUI Plugin Demo 4(Element Blocking Examples)
    jQuery BlockUI Plugin Demo 3(Page Blocking Examples)
    jQuery BlockUI Plugin Demo 2
    <configSections> 位置引起的错误
    关于jQuery的cookies插件2.2.0版设置过期时间的说明
    jQuery插件—获取URL参数
  • 原文地址:https://www.cnblogs.com/shujiying/p/12357193.html
Copyright © 2020-2023  润新知