JDK1.8源码泛读之Hashmap的hash算法

hash的核心方法之一就是键key的hash值的算法,因为这牵扯到键值对的桶查找,从源码看有以下两个地方最终决定了hash值的大小:

 1     public V put(K key, V value) {
 2         return putVal(hash(key), key, value, false, true);
 3     }
 4 
 5     //获取对象第一次hash值
 6     static final int hash(Object key) {
 7         int h;
 8         return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
 9     }
10 
11     final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
12                    boolean evict) {
13         Node<K,V>[] tab; Node<K,V> p; int n, i;
14         if ((tab = table) == null || (n = tab.length) == 0)
15             n = (tab = resize()).length;
16         // 根据hash值 取到hash表的index (n - 1) & hash
17         if ((p = tab[i = (n - 1) & hash]) == null)
18             tab[i] = newNode(hash, key, value, null);
19         else {
20         .....省略
21         }
22      }

 截取以上源码从key,到找到hash桶的index一共经历了两步:
1、(h = key.hashCode()) ^ (h >>> 16)
h>>>16 无符号向右移16位,相当于int类型的hashcode和自身无符号右移的进行了一次异或操作。
相当于混合了原始hashcode高低16位,从而达到扰动作用。

比如:
h=hashcode():11111111 11111111 11110000 11101010
异或
h>>>16        :00000000 00000000 11111111 11111111
第一步结果=   11111111 11111111 00001111 00010101

2、(n - 1) & hash
第一步结果和hashmap长度进行与操作,而hashmap在设计之初,就把长度n设计成了2的整数次幂,
因为这样,正好相当于一个“低位掩码”,比如n为16,那么二进制标识为:
00000000 00000000 00000000 00001111

再与第一步结果与操作:
11111111 11111111 00001111 00010101
00000000 00000000 00000000 00001111  &
00000000 00000000 00000000 00000101
= 高位全部清零:101 即结果为5

(n-1)& hash的结果正好都是分布在n的范围内。

转载于:https://www.cnblogs.com/blogsfuh/articles/8561558.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值