标签:为什么 href 操作 log .net lock 链接 分享 运行
下面是HashTable源码中的put方法:
注意上面注释标注的地方:
HashTable对于元素在哈希表中的坐标算法是:
HashMap中哈希算法比HashTable中的稍微复杂一点。总体可以分为两步:
上面代码中,首先是一个三目运算符,判断key是不是等于null,等于null,则返回0作为哈希值。否则,运算(h=key.hashCode()) ^ (h >>> 16),将key的哈希值的高位与低位异或的结果作为低位,改为不变。
‘>>>’是无符号右移操作,高位补0.
为什么要这么做呢?下面这一点讲了过后我们就明白了
同样以put方法为例
从最后一行我们可以看出,HashMap的哈希坐标计算方法是: (n - 1) & hash,其中hash就是我们第一点讲的改进哈希码。
举例分析如下,假设key的原始哈希值是’1111 1111 1111 1111 1111 0000 1110 1010’
(ps:图片来自:https://blog.csdn.net/john_520/article/details/57415084)
我们注意到,在上面这种哈希表长度较小的情况下,哈希码只有低4位与表的长度进行了关联性计算。这会造成哈希码的不充分使用,从而更容易引起哈希冲突。为了充分利用哈希码的高位,HashMap通过(h=key.hashCode()) ^ (h >>> 16)运算,将高位与低位异或,使得即使在表长较小的情况下,高位也能参与计算,使得冲突的概率减小了。
我在Stack Overflow上找到了一个解答:
意思是说:“规范的解决方法是将哈希值与表长取模,而这个方式((n - 1) & hash
)武汉英语学校充分利用了HashMap的表长是2的整数次幂的事实,使用效率较高的位与运算(取模的高度优化)来替代昂贵的取模运算。”
实际上这两种方式的实质是一样的,它只是利用了这样一个事实:在n是2的幂的情况下,(n - 1) & hash 等同于 hash%h。
我们以10为例,演示如下:
可以看到,两种方式的计算结果是相同的(这不是巧合),这实际上是一个数学规律。
在源码中有这样一个方法:
这个方法的作用如注释所说,是求大于cap的最小2的整数次幂。在用户指定的初始容量不是2的幂时,HashMap会调用该方法将其变得符合要求。此后,每次扩容时是这样的:
直接使用oldCap<<1来将容量扩大为原来的2倍,即乘以21。
我对JDK源码的阅读和中文注释都已经同步到Github,欢迎英语阅读困难户前往查看:)
链接是:https://github.com/Dodozhou/JDK,喜欢的话别忘了star哦。
HashMap与HashTable的哈希算法——JDK1.9源码阅读总结
标签:为什么 href 操作 log .net lock 链接 分享 运行
原文地址:https://www.cnblogs.com/zhangyiqinga/p/9753642.html