为什么hashmap的容量必须是2的n次幂

手把手带你编写miniQMT实盘量化执行程序(3) | 交易系统 本文介绍了miniQMT实盘量化执行系统的核心交易系统代码,重点讲解了其模块化设计和工作流程。系统采用主控类LiveSystem管理交易全流程,包含初始化引擎、交易日判断、交易时段划分(开盘前、盘中、收盘等)、主循环调度和异常处理等核心功能。作者详细解析了系统如何实现365天不间断运行、精准判断交易日、分阶段执行交易策略等功能,并强调系统的稳定性和异常处理机制。 阅读详情

 

要明白为什么是2的n次幂,这要从hashmap的hash方式说起,hashmap的容量期望就是用来均匀散列存放map中的元素。hashmap根据hash值把元素放到hashmap内部数组的一个位置上。

1、为什么hashmap的容量必须是2的n次幂??

我们不妨先看看hashCode的原理,以String为列,获取hashCode的方法源码

    public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            char val[] = value;
            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }

可以看出任何对象的hashCode方法返回一个对应的int类型的结果,所以hashCode的取值范围是-2^31 ~ (2^31-1),即-2147483648~2147483647。

(值得注意的是:两个对象equals相等,hashCode一定相等,hashCode相等,equals不一定相等,从上段代码hashCode源码中可以得出这个结论,会存在不同的数,计算出相同的hashCode)

当要存入map中的条目数为n(0 < n <= 1073741824)的时候,这n个数要散列分布到map数组中,那么map数组的长度为多少,才能使得元素在map数组最为呈现散列均匀分布,又不浪费空间呢?那么就是要求每个数通过某种算法,填入到数组表中的概率是相等的。这种算法最容易想到的就是取模运算。

我们联想下通过运算能不能达到类似效果呢,因为计算机本身就是通过位运算完成所有计算的,通过测试发现位运算比模运算快约27倍。怎么个位运算,使得n个元素能在有指定数组长度的情况下,得到散列分布索引值呢?

参考hashMap获取索引的算法源码

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

indexFor中的h是hashCode通过变换之后的值。怎么变换呢?为什么要变换呢?hashCode结果是一个32位的二进制数,如果直接用如此长的二进制数和目标length-1直接进行与运算结果为怎么样呢?答案是高位(也就是左边的位)会大量丢失。看看下面例子

如果两个数的hashCode分别是

11001110 11001101 11011101 00111110

11001110 11001111 11011101 00111110

只有其中第15位不一样(任何高位不一样都可以,假如我们以16位为划分,任何两个高16位不一样,低16位一样的数),这两个hashCode与length-1做与运算,当length<2的16次方时(1<<16 = 65536)得到两个hashCode & length-1 的结果一样,这样的两个数,却产生了相同的hash结果,于是hashMap想到了一种处理方式:将hashCode的高16位于低16位进行异或运算,其实吧用普通话说就是把高16位的特征放到低16位中,让低低16位同时拥有了高16的特征。这样,在与length-1做与运算时结果就不一样了。其计算过程如下:假如有hashCode a=11001110 11001111 11011101 00111110

int a =  11001110 11001111 11011101 00111110

a >>> 16 = 00000000 00000000 11001110 11001111

a ^ (a >>> 16)

11001110 11001111 11011101 00111110
00000000 00000000 11001110 11001111
=
11001110 11001111 00010011 11110001

用java代码表达 

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

hashCode结果是32位int 结果,将32位的结果做变换,可以从下面例子来研究下

int a =  11001110 11001111 11011101 00111110

a >>> 16 = 00000000 00000000 11001110 11001111

a ^ (a >>> 16)

11001110 11001111 11011101 00111110
00000000 00000000 11001110 11001111
=
11001110 11001111 00010011 11110001

在算法上可以看出,32位hashcode中保持高16位不变,高16与低16异或结果作为新的低16位。然后用hash得到的结果传入方法indexFor获取到hashMap的索引。

hash与n-1 做与运算,这样既在容量远小于1<<16(往往hashmap的容量远小于65535) 的情况下,hash & (n-1),在计算中只有低位((n-1)对应的二进制数相同的位数)参与&运算,计算效率高,同时也保证的hash的高16位参与了索引运算。这样得到的索引能呈较为理想的散列分布,在将条目放入hashMap中时,最大限度避免hash碰撞。

设hashMap容量为16,那么我们看下计算出来的索引值

11001110 11001111 00010011 11110001
&
00000000 00000000 00000000 00001111
=
00000000 00000000 00000000 00000001

索引=1,将该条目存入hash表标号为1的位置处

回到标题中的问题:为什么容量一定要是2的n次幂,只有当length=2的n次幂的时候,length-1的二进制表达 全部为1(15的二进制1111,31的二进制位11111),只有当length-1的全部位都1时,h & (length-1)的结果才能均匀散列在数组中。这时,取模和与运算两种运算才是等价不等效的。至此就解释完了为什么hashMap的容量必须是2的整数次幂。

2、hashmap怎么去计算容量呢?怎么确保程序员传入的值是2的n次幂呢,答案是不能保证。那就只能通过内部算法hashMa自己来实现保证。

先不考虑扩容的情况下,通过传入我们自定义的容量值来构造HashMap实例

    public HashMap(int initialCapacity) {
        // DEFAULT_LOAD_FACTOR = 0.75
        this(initialCapacity, DEFAULT_LOAD_FACTOR);
    }

怎么保证传入的容量一定2的整数次幂,可以从源码来看,通过下面方法等到保证,结果一定是2的整数次幂,结果是大于等于initialCapacity的最小2的整数次幂。

n |= n >>> 1,  符号 | 为或运算,n 与 n>>>1 进行或运算,然后赋值给n

    static final int tableSizeFor(int cap) {
        int n = cap - 1;
        n |= n >>> 1;
        n |= n >>> 2;
        n |= n >>> 4;
        n |= n >>> 8;
        n |= n >>> 16;
        return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
    }

当不指定Hashmap容量是,初始化默认容量为16,当往HashMap中put时,会检查当前hash表中的条目数是否大于容量的0.75倍,如果满足大于容量的0.75,hashMap调用resize方法,新容量 = 原来容量 x 2,在resize时将原来的容量翻倍,然后把之前所有条目复制一遍放入扩容之后的hash表中,这是非常好性能的操作,所以在已知容量数量的情况下避免扩容的情况发生。


 

7.1华为OD机试真题 新系统 - 仓库盘点 (Java/Py/C/C++/Js/Go) 7.1华为OD机试真题 新系统 - 仓库盘点 (Java/Py/C/C++/Js/Go) 阅读详情

相关推荐

STM32C8T6HAL库实战:MAX30102心率血氧检测与OLED多级菜单一体化方案

本文详细介绍了基于STM32C8T6和HAL库的MAX30102心率血氧检测与OLED多级菜单一体化方案。内容涵盖硬件连接、CubeMX工程配置、传感器驱动移植、数据滤波算法、OLED显示驱动以及高效的多级菜单系统设计,旨在提供一个稳定、实用且易于移植的嵌入式健康监测项目参考。

weixin_29256771的博客 397

HashMap容量为什么是2的n次方?如何做到的?

HashMap无疑是我们最常用的集合之一了,当我们调用HashMap(9)构建map的时候,它的容量是多少呢? 划重点!HashMap(9)构建的map的容量是16!!!这也就引出了下面的问题: HashMap的容量为什么是2的n次方?HashMap是如何保证容量是2的n次方的? HashMap容量取2的n次方,主要与hash寻址有关。在put(key,value)时,putVal()方法中通过i = (n - 1) & hash来计算key的散列地址。其实,i = (n - 1) &

进击的Coder*的博客 7423

QMT量化交易桥接方案深度对比:从MiniQMT淘汰说起

量化交易系统中的API桥接,本质是解决本地终端与底层交易引擎之间的通信瓶颈。其核心原理在于绕过GUI封装、直连确定性执行层,从而获得低延迟、高可靠、可监控的指令通路。技术价值体现在策略实盘一致性提升、毫秒级响应保障及运维可控性增强。典型应用场景包括打板策略、T+0套利、高频网格等对时效与稳定性双敏感的自动化交易。本文聚焦国金证券QMT专业版生态,系统剖析DLL注入、HTTP反向代理、IPC共享内存与官方HTTP API四大桥接路径的性能边界、合规风险与工程落地成本,尤其深入解析qmt终端 client is

weixin_33892359的博客 457

hashmap扩容为什么是2的幂

HashMap的初始容量都是2的n次幂的形式存在的,而扩容也是2倍的原来的容量进行扩容,也就是扩容后的容量也是2的n次幂的形式存在的,下面就来说明一下为什么是2的n次幂的形式! 先来看一下源码,也就是向HashMap中添加元素,或者扩容时是怎么存放元素的。 第一个截图是向HashMap中添加元素putVal()方法的部分源码,可以看出,向集合中添加元素时,会使用(n - 1) & hash ; n = table.length的计算方法来得出该元素在集合中的位置;而第二个截图是HashMap扩容

一个搬砖工人 1922

5分钟搞定Nano-Banana图片编辑API对接:从Base64编码到生成图片全流程

本文详细介绍了如何快速对接Nano-Banana图片编辑API,基于gemini-2.5-flash-image-preview模型,从环境准备、Base64编码到API调用的全流程。通过实战示例和优化技巧,帮助开发者高效集成AI图片处理能力,提升产品竞争力。

dog123的博客 259

遗传病变异注释预测工具安装系列之------Exomiser 安装及bug处理

Exomiser是一个Java程序,它从全外显子组或全基因组测序数据中发现潜在的致病变异。 Java 版本必须为1.8以上。 Exomiser 最新版本下载 wget -c https://github.com/exomiser/Exomiser/releases/download/11.0.0/exomiser-cli-11.0.0-distribution.zip unzip ...

qq_37329349的博客 1535

一文看懂HashMap扩容为什么总是2的次幂

点击上方“后端技术精选”,选择“置顶公众号”技术文章第一时间送达!作者:helloword先生https://blog.youkuaiyun.com/u010841296/HashMap是根据key...

Java笔记虾 3217

如何免费访问和使用Gemini API?

Gemini Ultra具有最先进的性能,在几个指标上超过了GPT-4的性能。它是第一个在大规模多任务语言理解基准测试中超越人类专家的模型,该基准测试57个不同学科的世界知识和解决问题的能力。Gemini是谷歌迄今为止开发的最先进、最庞大的AI模型。它为多模态而建,理解并处理不同类型的数据,比如文本、代码、音频、图像和视频。下面我们将加载Masood Aslami的图像,并用它来测试Gemini Pro Vision的多模态性。有了Gemini可以为查询提供图像、音频和文本,获得几乎完美的答案。

java_cjkl的博客 1万+

HashMap每次扩容时,为什么都必须是2的N次方?

HashMap的底层是通过的数据结构来存放数据的。我们知道,那么问题来了,为什么HashMap会将首次初始化容量设置为16,而后续每次扩容都是之前的2倍?而不是像ArrayList首次为10,后续为1.5倍呢?这可是我们在面试时的一个高频考点哦!

一一哥 2618

AI原生SaaS应用的自动化运维体系构建

随着ChatGPT掀起的AI原生应用浪潮,越来越多SaaS(软件即服务)产品开始以"AI优先"的方式设计——从用户交互到核心功能,都深度依赖机器学习模型(如推荐算法、智能客服)、实时数据流(如用户行为分析)和弹性算力(如大模型推理)。这类应用的运维需求与传统SaaS完全不同:传统运维像"修水管",哪里漏了补哪里;AI原生运维则像"照顾会成长的宠物",需要实时感知模型状态、数据变化和流量波动,主动调整资源。

AI天才研究院 1080

【乐企】开票控制服务

例子:企业信息初始化。

九七的博客 452

HashMap 的长度为什么是 2 的 N 次方呢?

2. 扩容时的重新哈希: 当 HashMap 的元素个数达到容量的 3/4 时(Java 8 及之前为 0.75,Java 8 及之后为 0.625),HashMap 会进行扩容操作。这样在重新计算哈希值时,只需将原来的哈希值的高位与新的容量进行与操作(取模),就可以得到新的位置。1. 散列冲突的解决: 在 HashMap 中,元素存储位置是根据元素的键的哈希值决定的。采用长度为 2 的幂次方可以确保通过哈希值的某些位掩码(取模操作)来定位到数组中的位置,这样可以减少哈希碰撞的概率,提高查找效率。

NZC2237的博客 1623

Python3实现基于ARIMA模型来预测茅台股票价格趋势

ARIMA(Autoregressive Integrated Moving Average)模型是一种广泛使用的时间序列分析方法,它可以用于对未来的数据进行预测。ARIMA模型由自回归模型(AR模型)、差分整合模型(I模型)和移动平均模型(MA模型)组成,因此也被称为ARIMA(p,d,q)模型。其中,p表示自回归阶数,d表示差分阶数,q表示移动平均阶数。具体来说,ARIMA模型可以通过以下步骤进行建模:数据预处理:对时间序列进行平稳性检验,如果不满足平稳性,则进行差分操作。

m0_64336780的博客 2万+

HashMap:为什么容量总是为2的n次幂

HashMap:为什么容量总是为2的n次幂 1)、HashMap是根据key的hash值决定key放到哪个桶中,通过tab[i = (n - 1) &amp; hash]公式计算得出 这里的n是HashMap的容量,因为n永远是2的次幂,所以n - 1通过二进制表示,永远都是末尾连续1的形式表示(如00001111、00000011),当(n - 1) 和hash做与运算时,会保留hash中后x位...

hxt的博客 5194

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

HashMap初始容量为什么是2的n次幂及扩容为什么是2倍的形式

接着上一篇博客,上一篇博客说明了HashMap的初始容量都是2的n次幂的形式存在的,而扩容也是2倍的原来的容量进行扩容,也就是扩容后的容量也是2的n次幂的形式存在的,下面就来说明一下为什么是2的n次幂的形式! 先来看一下源码,也就是向HashMap中添加元素,或者扩容时是怎么存放元素的。 第一个截图是向HashMap中添加元素putVal()方法的部分源码,可以看出,向集合...

Apeopl的博客 4万+

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

HashMap——HashMap的容量为什么是2的n次幂

由此我们可以看出当哈希数组长度为奇数时是极易发生哈希碰撞,导致我们的数组空间不能被充分利用且。过长,降低查找的效率而哈希数组长度为偶数时发生哈希碰撞的概率是比较小的,所以数组长度在考虑。来计算索引值,key&(length-1)这两种计算方式并无太大区别,只是相对于。为key%(length-1)但这样在计算机中计算效率比较低,所以我们采用。被设置为16,而在我们通过key去计算哈希值(索引值时)计算一般采用。我们在计算哈希值时发生哈希碰撞是不可避免的,但是怎样才能。位运算:都为1时则为1否则为0。

Lemon_man_的博客 399

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

HashMap、ConcurrentHashMap的容量为什么总是2的n次幂

HashMap、ConcurrentHashMap的容量为什么总是2的n次幂

just_for_that_moment的博客 545

HashMap初始容量为什么是2的n次幂及扩容为什么是2倍的形式?

前言 逛了一圈发现大家对于这个问题的回答写的都比较散乱,简而言之两点原因: 1.为了保证得到的新的数组索引和老数组索引一致 2.rehash时的取余操作,hash % length == hash & (length - 1)这个关系只有在length等于二的幂次方时成立,位运算能比%高效得多 论述 1.为了保证得到的新的数组索引和老数组索引一致。HashMap的初始容量是2的n次幂,扩容也是2倍的形式进行扩容,是因为容量是2的n次幂,可以使得添加的元素均匀分布在HashMap中的数组上,减少has

Apollo的博客 1万+

HashMap的数组容量为什么是2的N次幂

HashMap的数组容量为什么是2的N次幂,首先我们要清楚数组的索引值是0到N-1,而hashCode的计算范围是42亿,也就是所有对象的hashCode有42亿种可能,我们要把它丢到这16的长度的数组里面时,我们应该怎么做?怎么将42亿种可能变为0到N-1种可能,通常我们会想到用取模的方法来计算,但是它有两个缺点: 1、负数求余还是负数 2、 性能较慢(对比位运算) 我们来看看HashMap源码是怎么做的,它用的是不是取模运算呢?向HashMap中添加元素,或者扩容时是怎么存放元素的。 第一张图,向

weixin_44421311的博客 1221

为什么jdk1.8 HashMap的容量一定要是2的n次幂

一、jdk1.8中,对“HashMap的容量一定要是2的n次幂”做了严格控制   1.默认初始容量: [Java]纯文本查看复制代码 ? 1 2 3 4 /** * The default initial capacity - MUST be a power of two.(默认初始容量——必须是2的n次幂...

黑马程序员广州中心的专栏 860

为什么HashMap的容量必须为大于该容量的最小的2的n次幂

调用HashMap的put方法将一个键值对存到map中,会先计算key的散列值。该散列值是int基本类型,int的范围为~,用这个散列值来确定map的数组下标(jdk8之前HashMap的数据结构是数组+链表,jdk8之后又加上了红黑树)。但这散列值太大,map的容量不可能这么大,会内存溢出。所以需要通过一种方式将这个key的散列值与map的容量对应起来。比如说将散列值与map容量取模,这样得到的结果一定小于容量了,就可以拿来做数组下标了,但取模计算的速度较慢。jdk采用了这种方式计算下标: (n -

jingzuangod的博客 989

HashMap的容量为什么是2的n次幂小记

HashMap的容量为什么是2的n次幂,和这个(n - 1) & hash的计算方法有着千丝万缕的关系,符号&是按位与的计算,这是位运算,计算机能直接运算,特别高效,&的计算方法是,只有当对应位置的数据都为1时,运算结果也为1,当HashMap的容量是2的n次幂时,(n-1)的2进制也就是1111111***111这样形式的,这样与添加元素的hash值进行位运算时,能够充分的散列,使得添加的元素均匀分布在HashMap的每个位置上,减少hash碰撞,下面举例进行说明 由图...

cj_eryue的博客 502

HashMap的容量为什么是2的n次幂

总结:为了减少哈希冲突 为什么能减少哈希冲突,因为容量的大小跟确定元素在桶中的位置有关, 元素在桶中的位置由(n-1)&hash计算得来 当容量大小不够大时,元素的位置主要用的hash低位的信息,那么结合&操作,&的另一个数最好低位全是1,而2的整数次幂-1的低位全是1,这样&才有意义;否则结果就肯定是0那么&就没有意义,冲突概率增加 ...

alphadunk的博客 253
上一篇: mysql 数据库索引b+树深度问题
下一篇: hashMap1.7头插法及扩容
小涛_foxiaotao
博客等级 码龄14年 2粉丝 52原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值