关于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倍
关于HashMap初始化容量问题的更多相关文章
- HashMap初始化容量过程
集合是Java开发日常开发中经常会使用到的,而作为一种典型的K-V结构的数据结构,HashMap对于Java开发者一定不陌生.在日常开发中,我们经常会像如下方式以下创建一个HashMap: Map&l ...
- hashmap 为什么初始化容量是2的幂次方
个人理解 做下记录,不正确的地方望不吝赐教 这是hashmap初始化容量时候 对容量大小做的处理,保证初始化容量为最近的2的幂次方(JDK1.8) static final int tableSize ...
- 阿里巴巴Java开发手册建议创建HashMap时设置初始化容量,但是多少合适呢?
集合是Java开发日常开发中经常会使用到的,而作为一种典型的K-V结构的数据结构,HashMap对于Java开发者一定不陌生. 关于HashMap,很多人都对他有一些基本的了解,比如他和hashtab ...
- 为什么要指定HashMap的容量?HashMap指定容量初始化后,底层Hash数组已经被分配内存了吗?
为什么要指定HashMap的容量? 首先创建HashMap时,指定容量比如1024后,并不是HashMap的size不是1024,而是0,插入多少元素,size就是多少: 然后如果不指定HashMap ...
- jdk1.8 HashMap底层数据结构:深入解析为什么jdk1.8 HashMap的容量一定要是2的n次幂
前言 1.本文根据jdk1.8源码来分析HashMap的容量取值问题: 2.本文有做 jdk1.8 HashMap.resize()扩容方法的源码解析:见下文“一.3.扩容:同样需要保证扩容后的容量是 ...
- 为什么jdk1.8 HashMap的容量一定要是2的n次幂
一.jdk1.8中,对“HashMap的容量一定要是2的n次幂”做了严格控制 1.默认初始容量: [Java] 纯文本查看 复制代码 ? 1 2 3 4 /** * The default init ...
- 我说HashMap初始容量是16,面试官让我回去等通知
众所周知HashMap是工作和面试中最常遇到的数据类型,但很多人对HashMap的知识止步于会用的程度,对它的底层实现原理一知半解,了解过很多HashMap的知识点,却都是散乱不成体系,今天一灯带你一 ...
- Java 中 HashMap 初始化时赋值
1.HashMap 初始化的文艺写法 HashMap 是一种常用的数据结构,一般用来做数据字典或者 Hash 查找的容器.普通青年一般会这么初始化:HashMap<String, Strin ...
- HashMap的容量大小增长原理(JDK1.6/1.7/1.8)
. 前言 HashMap的容量大小会根据其存储数据的数量多少而自动扩充,即当HashMap存储数据的数量到达一个阈值(threshold)时,再往里面增加数据,便可能会扩充HashMap的容量. 可能 ...
随机推荐
- 挑战黑客极限:Pwn2Own 2015成史上“最难”黑客大赛
Pwn2Own是全球最著名.奖金最丰厚的黑客大赛,由美国五角大楼入侵防护系统供应商TippingPoint赞助.近日Pwn2Own 2015公布全新的比赛规则,本届赛事难度超高.史无前例,包括VUPE ...
- [置顶] Eclipse显示中文 在线安装教程
准备工作: 1,一个完整的Eclipse软件: 2,加载软件地址:http://download.eclipse.org/technology/babel/update-site/R0.11.0/ke ...
- 详解REMOTE_ADDR,HTTP_CLIENT_IP,HTTP_X_FORWARDED_FOR
转载自:http://www.cnblogs.com/lmule/archive/2010/10/15/1852020.html 看ecshop的lib_base.php的时候里面获取客户端真实ip的 ...
- 面对对象之差异化的网络数据交互方式--单机游戏开发之无缝切换到C/S模式
上一篇这里描写叙述了一个关于差异数据在开发过程中的一个长处,这里来演示另外一个特点:单机开发之无缝切换到C/S模式 一般C/S模式都面临一个问题: 就是开发过程中的调试难题,由于涉及到client和服 ...
- (C++)浅谈using namespace std
1.<iostream>和<iostream.h> 在你的编译器include文件夹里面可以看到,二者是两个文件,里面的代码是不一样的. 后缀为.h的头文件c++标准已经明确提 ...
- C#基础视频教程7.2 如何编写简单游戏
前面一小节我们实现了简单的碰撞检测,但是实际上游戏的对象并不是一个标准的矩形(小鸟是一个不规则的物体,其实碰撞的管道也是不规则物体),所以如果真的要做的比较完美,我们自己要写一个方法,能够导入一个图像 ...
- (step6.1.1)hdu 1879(继续畅通工程——最小生成树、kruscal)
题目大意:输入一个整数n,表示有n个村庄.在接下来的n(n-1)/2行中,每行有4个整数begin end weight flag.分别表示从begin到end之间可以连通 ,他们之间的费用为w ...
- Colours
A colour is an object representing a combination of Red, Green, and Blue (RGB) intensity values. Val ...
- JavaScript严格模式下this指向
一般认为:严格模式下this不允许指向全局对象.是函数体是否处于严格模式! 如:http://www.ruanyifeng.com/blog/2013/01/javascript_strict_mod ...
- linux(Centos)下编译安装gcc4.8.2
欢迎转载.转载请注明原文地址:http://blog.csdn.net/majianfei1023/article/details/46811159 近期要用到c++ 11,所以没办法仅仅得把那台ce ...