关于HashMap初始化容量问题

使用阿里云代码规范插件扫描后出现以下提示:

hashmap should set a size when initalizing,即hashmap应该在初始化时设置一个大小

在网上搜到一篇讲解(https://www.cnblogs.com/coderxuyang/p/3718856.html),如下:

在元素的装载数量明确的时候HashMap的大小应该如何选择。

今天看到美团招聘给出了一道小题目,关于HashMap的性能问题。问题如下:

java hashmap,如果确定只装载100个元素,new HashMap(?)多少是最佳的,why?

要回答这个问题,首先得知道影响HashMap性能的参数有哪些。咱们翻翻JDK。

在JDK6中是这么描述的:

HashMap的实例有两个参数影响其性能:初始容量和加载因子。

首先我们来看初始容量和加载因子的定义。

容量是哈希表中桶的数量,初始容量只是哈希表在创建时的容量。

加载因子是哈希表在其容量自动增加之前可以达到多满的一种尺度。

当哈希表中条目的数目超过 容量乘加载因子 的时候,则要对该哈希表进行rehash操作,从而哈希表将具有大约两倍的桶数。(以上摘自JDK6)

HashMap默认的加载因子是0.75 .它在时间和空间成本上寻求了一种折中。

回到本文的问题。根据JDK中的描述,如果这个只装载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为哈希表的长度。

134-1 = 128 + 6 -1;

那么 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次方,那么,所有的哈希桶均有被使用的可能。

再次回到美团提出的问题,与134最靠近的2^n无疑是128。

如果只修改HashMap的长度而不修改HashMap的加载因子的话,HashMap会进行rehash操作,这是一个代价很大的操作,所以不可取。

那么应该选择的就应该是256。

而由于空间加大和有效利用哈希桶,这时的哈希碰撞将大大降低,因此HashMap的读取效率会比较高。

所以,最后结论就是:HashMap的大小应该设置为256。

结果的补充:其实在Java中,无论你的HashMap(x)中的x设置为多少,HashMap的大小都是2^n。2^n是大于x的第一个数。因为HashMap的初始化代码中有以下这行代码:

 int capacity = 1;while (capacity < initialCapacity)capacity <<= 1;

但是这就带来了一个问题,如果x=100,那么HashMap的初始大小应该是128.但是100/128=0.78,已经超过默认加载因子(0.75)的大小了。因此会resize一次,变成256。所以最好的结果还是256。

最后发个参考链接:http://www.iteye.com/topic/539465

另,总结StringBuffer、ArrayList、HashMap的扩容:

StringBuffer:内部实现是一个字符数组。初始默认大小为16,当然也可以在其构造方法中进行设置。当新添加字符或字符串时,发现数组容量不够。这个时候就需要使用Array.copyOf()方法进行扩充。扩充的新的数组大小等于,(原始容量*2+2)和(数组实际字符个数+新增的字符长度)之间的较大值。

ArrayList:内部实现是一个Object的数组。初始默认大小为0,当然也可以在其构造方法中设置。当添加一个Object时,默认扩充数组容量为10。然后每次扩充的新的数组大小等于,(原始容量*3/2)和(数组的长度+1)之间的较大值。根据每次增加一个Object,可得该情况每次扩充的固定大小为3/2。当初始大小为手动设置的时候,每次扩充的新的数组大小等于,(原始容量*3/2)和(数组的长度+1)之间的较大值。

HashMap:内部实现是一个Entry的数组,默认大小是空的数组。初始化的容量是16,加载因子是3/4(当数组元素数量大于总容量的加载因子的时候,扩充数组)。当默认不是空的数组时,当达到加载因子的比例的时候,每次扩充初始容量的2倍

转载自https://www.cnblogs.com/tiancai/p/9558895.html

关于HashMap初始化容量问题相关推荐

  1. android 设置setmultichoiceitems设置初始化勾选_阿里巴巴Java开发手册建议创建HashMap时设置初始化容量,但是多少合适呢?...

    集合是Java开发日常开发中经常会使用到的,而作为一种典型的K-V结构的数据结构,HashMap对于Java开发者一定不陌生. 关于HashMap,很多人都对他有一些基本的了解,比如他和hashtab ...

  2. 设置作者_阿里Java开发手册建议创建HashMap时设置初始化容量,但多少合适

    集合是Java开发日常开发中经常会使用到的,而作为一种典型的K-V结构的数据结构,HashMap对于Java开发者一定不陌生. 关于HashMap,很多人都对他有一些基本的了解,比如他和hashtab ...

  3. 阿里巴巴Java开发手册建议创建HashMap时设置初始化容量,但是多少合适呢?

    集合是Java开发日常开发中经常会使用到的,而作为一种典型的K-V结构的数据结构,HashMap对于Java开发者一定不陌生. 关于HashMap,很多人都对他有一些基本的了解,比如他和hashtab ...

  4. 为什么要设置HashMap的初始化容量

    经常在初始化hashmap的时候出现如下情况 <阿里巴巴Java开发手册>解释 那么,为什么要这么建议?你有想过没有. 我们先来写一段代码在JDK 下面来分别测试下,在不指定初始化容量和指 ...

  5. hashmap应用场景_Java初学者进阶系列:HashMap的容量与性能

    1. HashMap的容量与性能 HashMap的性能受到两个参数的影响:初始化容量和负载因子,下面来详细讲述这几个关键问题. 1.1 Initial Capacity与Load Factor Ini ...

  6. jdk8 HashMap初始化和扩容机制

    工作中大家讨论HashMap设置初始化容量的问题,写篇文章好好聊聊. 一.jdk8 HashMap初始化和扩容机制 以下面的代码为例 Map<String, String> map = n ...

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

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

  8. HashMap的容量与扩容

    阅读JDK源码是提高我们技术很好的途径,其中HashMap的设计是非常优秀的,但是其中定义了许多变量,让人头昏目眩,那么这些变量都是什么意思呢 HashMap中的变量 本篇文章主要关注的字段是DEFA ...

  9. hashMap的容量(capacity)为什么必须是是2的n次方

    HashMap的容量(桶的数量)为什么要是2的n次方 查看hashmap的源码可以发现,如果new一个hashmap对象不指定容量(capacity)的话,hashmap的默认初始化容量是16,也就是 ...

最新文章

  1. JDBC executeBatch 抛出异常停止
  2. 上验证cudnn是否安装成功_windows和linux上的tensorflow安装(极简安装方法)
  3. .NET跨平台之旅:博问站点迁移至ASP.NET Core on Linux并发布上线
  4. 【SpringCloud】第五篇: 路由网关(zuul)
  5. 程序员加班一周休病假,犯了小错误遭开除,老板怒斥程序员不中用
  6. Java 32 进制_32位数字的十六进制表示
  7. 【codeforces】【比赛题解】#937 CF Round #467 (Div. 2)
  8. Android usb audio调用流程(二)
  9. python开发环境及网络基础
  10. 房屋租赁管理系统mysql(含论文)
  11. FeHelper工具(Web前端助手)
  12. InstantClient+PLSQL安装配置教程
  13. 编译原理逆波兰式实验java_【实验三】—— 逆波兰式生成实验报告
  14. c语言的简单的分数求和
  15. 用手机APP的方式实现PLC远程监控
  16. 精选了国内外 6 个接私活的网站,供大家赚钱!
  17. vw css什么单位,CSS vw单位
  18. if与switch的性能比较
  19. 自由天空XP/2K3封装工具 Easy Sysprep v2.0 正式版封装教程
  20. 犀牛Rhino 6破解版安装后底部与导航栏英文解决方法 及在Rhino中使用python编译器

热门文章

  1. cookie分号后面没有值_浏览器Cookie介绍
  2. vuejs简单介绍特点
  3. js之iframe子页面与父页面通信
  4. Discuz X1.5 X2.5 X3 UC_KEY Getshell Write PHPCODE into config/config_ucenter.php Via /api/uc.php Vul
  5. 普林斯顿公开课 算法1-5:算法理论
  6. javascript如何用户的判断操作系统
  7. freebsd下支持LATEX书写数学公式的网站搭建
  8. 【网络小说推荐】纨绔才子
  9. php团队奖,PHP生成奖状
  10. gephi生成网络关系图_路网拓扑重建专题 (3) 网络图生成