首页 > 其他分享 >HashMap初始化容量

HashMap初始化容量

时间:2022-11-01 11:33:54浏览次数:85  
标签:初始化 那么 HashMap 容量 length 哈希


HashMap初始化容量

《阿里巴巴Java开发规约》中有提到:

【推荐】集合初始化时,指定集合初始值大小。
说明:HashMap使用如下构造方法进行初始化,如果暂时无法确定集合大小,那么指定默认值(16)即可:

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

那么HashMap的初始化值到底应该是多少呢?想要得出这个问题答案,必须先了解一下HashMap的部分特征

HashMap的实例有两个参数影响其性能:初始容量和加载因子
容量是哈希表中桶的数量,初始容量只是哈希表在创建时的容量。HashMap的默认大小为16
加载因子是哈希表在其容量自动增加之前可以达到多满的一种尺度。HashMap默认的加载因子是0.75 .它在时间和空间成本上寻求了一种折中。
当哈希表中条目的数目超过 ​​​容量 * 加载因子​​ 的时候,则要对该哈希表进行rehash操作,从而哈希表将具有大约两倍的桶数。

再回到正题,如果确定只装载100个元素,new HashMap()初始化容量多少是最佳的?

根据上文的推测,如果这个只装载100个元素的HashMap没有特殊的用途,那么为了在时间和空间上达到最佳性能,HashMap的初始容量可以设为 100/0.75 = 133.33。为了防止rehash,向上取整,为134。

但是还有另外一个问题,就是hash碰撞的问题。如果我们将HashMap的容量设置为134,那么如何保证其中的哈希碰撞会比较少呢?

除非重写hashcode()方法,否则,似乎没有办法保证。

HashMap在这也有一个解决方案就是选择下标方法:

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

其中h为key哈希后得到的值,length为哈希表的长度。

那么 length-1的二进制值的最后3位为101;
假设这100个装载的元素中他们的key在哈希后有得到两个值(h),他们的二进制值除了低3位之外都相同,而第一个值的低3位为011,第二个值的低3位为001;
这时候进行java的&预算,011 & 101 = 001 ;001 & 101 = 001;
他们的值相等了,那么这个时候就会发生哈希碰撞。

除此之外还有一个更加严重的问题,由于在101中第二位是0,那么,无论我们的key在哈希运算之后得到的值h是什么,那么在&运算之后,得到的结果的倒数第二位均为0;
因此,对于hash表所有下标的二进制的值而言,只要低位第二位的值为1,(例如0010,0011,0111,1111)那么这个下标所代表的桶将一直是空的,因为代码中的&运算的结果永远不会产生低位第二位为1的值。这就大大地浪费了空间,同时还增加了哈希碰撞的概率。这无疑会降低HashMap的效率。

那么如何才能减少这种浪费呢?最佳的方法当然是让length-1的二进制值全部位均为1.那么length的值是多少合适呢?
没错,length=2^n。
只要将hash表的长度设为2的N次方,那么,所有的哈希桶均有被使用的可能。

所以上面的答案应该为256

后话:
JDK并不会直接拿用户传进来的数字当做默认容量,而是会进行一番运算,最终得到一个2的幂
也就是说,无论你的HashMap(x)中的x设置为多少,HashMap的大小都是2n。2n是大于x的第一个数。

因此关于这个值的设置,在《阿里巴巴Java开发手册》有以下建议:

正例:initialCapacity = (需要存储的元素个数 / 负载因子) + 1。注意 负载因子(即loader factor)默认 为 0.75,如果 暂时 无法确定 初始 值大小,请设置 为 16。


标签:初始化,那么,HashMap,容量,length,哈希
From: https://blog.51cto.com/u_13351110/5812930

相关文章

  • 关于hashMap的容量为什么是2的幂次方数
    先看hashMap的构造方法publicHashMap(intinitialCapacity,floatloadFactor){if(initialCapacity<0)thrownewIllegalArgumentException(......
  • HashMap详解
    HashMap详解HashMap相关介绍HashMap是Java中的比较常见的集合,主要存放的是键值对,以key-value的形式存储,不是线程安全的。它里面的存储的key和value可以为null值,但是key......
  • 初始化centos环境脚本
    #!/bin/bashecho"java环境初始化开始"#功能描述:Centos8.5系统自动初始化脚本#自动配置:IP地址\Yum源\docer\docker-composev2.7.0\ZSH\Portainer\Cockpit\zabbix-agen......
  • 浅入浅出 1.7和1.8的 HashMap
    前言HashMap是我们最最最常用的东西了,它就是我们在大学中学习数据结构的时候,学到的哈希表这种数据结构。面试中,HashMap的问题也是常客,现在卷到必须答出来了,是必须会的知......
  • Java学习——初始化对象
    一、如何使用通过注释@PostConstruct标明是初始化方法@PostConstructpublicvoidinit(){}二、注意事项初始化方法和构造方法不同,构造方法只是生成了一个对象,而初始......
  • 【精彩内容分享】SoCC 2022 | 大规模云系统自动化容量评估的探索与落地 – DeepScalin
    以下内容来自公众号【蚂蚁技术风险TRaaS】1.前言在线服务提供商比如Google、Facebook、蚂蚁、腾讯等为了保证自身服务的SLO,在进行资源配置时通常会采取“保守”策略:即配置相......
  • go 切片长度与容量的区别
    ###切片的声明切片可以看成是数组的引用(实际上切片的底层数据结构确实是数组)。在Go中,每个数组的大小是固定的,不能随意改变大小,切片可以为数组提供动态增长和缩小的需求,但......
  • SpringMVC源码-DispatcherServlet初始化
    web容器启动后会实例化Servlet,会执行Servlet的init方法且只会执行一次。后续调用doService处理客户请求。DispatcherServlet的构造方法publicDispatcherServlet(){ su......
  • 计算机中显示出来的容量往往是硬盘容量的93%左右
    这是由于不同的单位转换关系造成的。在计算机中1GB=1024MB,而硬盘厂家通常是按照1GB=1000MB进行换算的。以120GB的硬盘为例进行举例说明:厂商计算方法:120GB=120000MB=12000000......
  • LcdTools如何编写初始化代码之--SPI指令
    在点屏过程中经常会碰到需要通过SPI接口对DriverIC下初始化代码后才能点亮,常见于LVDS、RGB屏,那如何在LcdTools上编写PX01SPI初始化代码呢?通过LcdTools帮助文档可以查看S......