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,并不均匀
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器