HashMap中如何确定元素的位置

向数组里 put 元素,必然需要知道数组的引用名称和要被 put 的位置的下标, HashMap 的 put 方法只有 key 和 value 两个参数,没有 int 类型的 index,那 HashMap 是如何确定每个元素会被存放到数组的哪个位置呢?

如何确定位置

这里需要提到indexFor方法,jdk1.7中有indexFor方法,jdk1.8里没有,但原理没变。1.8中用tab[(n - 1) & hash]代替但原理一样。

static int indexFor(int h, int length) {
return h & (length-1);
}

该方法利用了hash值与数组长度,计算得到索引

问题1:为什么用length-1

HashMap 的容量永远都是2的n次方,也就是说,table.length的二进制表示永远都是一个1,其余都是0的状态,例如2的4次方16是0001 0000,5次方32是0010 0000,如果不-1直接与h与运算,数组很多地方将永远不会被存入数据。会造成严重的空间浪费,更糟的是这种情况下,数组可以使用的位置比数组长度小了很多,这意味着进一步增加了碰撞的几率,减慢了查询的效率。

问题2:为什么用&,不直接取模%

位运算快于十进制运算,hashmap扩容也是按位扩容,这样同时也提高了运算效率。

 

Hash方法

static final int hash(Object key) {
   int h;
   return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

问题1:为什么不直接用hashCode,而要与(h >>> 16)做位运算

(1)为了让高位hashCode参与数组下标的计算,这样做可以让数组下标更加散列,减少Hash碰撞

(2)hashCode方法返回的是int整数类型,其范围为-(2 ^ 31)~(2 ^ 31 - 1),约有40亿个映射空间,而HashMap的容量范围是在16(初始化默认值)~2 ^ 30,HashMap通常情况下是取不到最大值的,并且设备上也难以提供这么多的存储空间,从而导致通过hashCode()计算出的哈希值可能不在数组大小范围内,进而无法匹配存储位置;

问题2:为什么是右移16位,不是14,15位

hash值的二进制码是32位,所以最理想的是折半,取16

问题3:为什么用^而不用&和|

因为&和|都会使结果偏向0或1,并不均匀

posted @   qwdsa019X  阅读(405)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
点击右上角即可分享
微信分享提示