我们知道在hashmap中要找到某个元素,需要根据key的hash值来求得对应数组中的位置。如何计算这个位置就是hash算法。前面说过hashmap的数据结构是数组和链表的结合,所以我们当然希望这个hashmap里面的元素位置尽量的分布均匀些,尽量使得每个位置上的元素数量只有一个,那么当我们用hash算法求得这个位置的时候,马上就可以知道对应位置的元素就是我们要的,而不用再去遍历链表
所以我们首先想到的就是把hashcode对数组长度取模运算,这样一来,元素的分布相对来说是比较均匀的。但是,“模”运算的消耗还是比较大的,能不能找一种更快速,消耗更小的方式那?java中时这样做的,

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

首先算得key得hashcode值,然后跟数组的长度-1做一次“与”运算(&)。看上去很简单,其实比较有玄机。比如数组的长度是2的4次方,那么hashcode就会和2的4次方-1做“与”运算。很多人都有这个疑问,为什么hashmap的数组初始化大小都是2的次方大小时,hashmap的效率最高,我以2的4次方举例,来解释一下为什么数组大小为2的幂时hashmap访问的性能最高。
看下图,左边两组是数组长度为16(2的4次方),右边两组是数组长度为15。两组的hashcode均为8和9,但是很明显,当它们和1110“与”的时候,产生了相同的结果,也就是说它们会定位到数组中的同一个位置上去,这就产生了碰撞,8和9会被放到同一个链表上,那么查询的时候就需要遍历这个链表,得到8或者9,这样就降低了查询的效率。同时,我们也可以发现,当数组长度为15的时候,hashcode的值会与14(1110)进行“与”,那么最后一位永远是0,而0001,0011,0101,1001,1011,0111,1101这几个位置永远都不能存放元素了,空间浪费相当大,更糟的是这种情况中,数组可以使用的位置比数组长度小了很多,这意味着进一步增加了碰撞的几率,减慢了查询的效率!

所以说,当数组长度为2的n次幂的时候,不同的key算得得index相同的几率较小,那么数据在数组上分布就比较均匀,也就是说碰撞的几率小,相对的,查询的时候就不用遍历某个位置上的链表,这样查询效率也就较高了。
说到这里,我们再回头看一下hashmap中默认的数组大小是多少,查看源代码可以得知是16,为什么是16,而不是15,也不是20呢,看到上面annegu的解释之后我们就清楚了吧,显然是因为16是2的整数次幂的原因,在小数据量的情况下16比15和20更能减少key之间的碰撞,而加快查询的效率。

所以,在存储大容量数据的时候,最好预先指定hashmap的size为2的整数次幂次方。就算不指定的话,也会以大于且最接近指定值大小的2次幂来初始化的,代码如下(HashMap的构造方法中):

// Find a power of 2 >= initialCapacity  int capacity = 1;  while (capacity < initialCapacity)   capacity <<= 1;

总结:
本文主要描述了HashMap的结构,和hashmap中hash函数的实现,以及该实现的特性,同时描述了hashmap中resize带来性能消耗的根本原因,以及将普通的域模型对象作为key的基本要求。尤其是hash函数的实现,可以说是整个HashMap的精髓所在,只有真正理解了这个hash函数,才可以说对HashMap有了一定的理解。

hashmap为什么容量是2的n次方相关推荐

  1. HashMap的容量(桶的数量)为什么要是2的n次方

    2019独角兽企业重金招聘Python工程师标准>>> HashMap为了存取高效,要尽量较少碰撞,就是要尽量把数据分配均匀,每个链表长度大致相同. 关键就在于把当前数据存放到哪一个 ...

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

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

  3. 被替换的项目不是替换值长度的倍数_面试官,为啥HashMap的长度是2的n次方?

    前言 HashMap的主干是一个数组,假设我们有3个键值对dnf:1,cf:2,lol:3,每次放的时候会根据hash函数来确定这个键值对应该放在数组的哪个位置,即index = hash(key) ...

  4. 关于HashMap初始化容量问题

    关于HashMap初始化容量问题 使用阿里云代码规范插件扫描后出现以下提示: hashmap should set a size when initalizing,即hashmap应该在初始化时设置一 ...

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

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

  6. HashMap最大容量为什么是2的32次方

    //默认的桶数组大小 static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; //极限值(超过这个值就将threshold修改为Intege ...

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

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

  8. hashmap 不释放空间_刁难问题,为什么HashMap默认容量为16加载因子为0.75

    前言:实际开发中我们大多数都是只能new HashMap<>来存储键值对,很少会去设置初始容量,虽然我们知道他的默认容量是16.但是在面试中,为了体现你个人好学的能力,还是会被经常问到为什 ...

  9. HashMap的容量与扩容

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

最新文章

  1. bug诞生记——隐蔽的指针偏移计算导致的数据错乱
  2. vue 不识别svg_vue中引用svg,vue引入svg不显示,vue引用svg配置,vue3.0+ts如何配置svg...
  3. asp.net ajax中文乱码的解决?2010-01-19 12:06
  4. android 组件化_Android 组件化路由框架设计(仿Arouter)
  5. 【BZOJ1206】【HNOI2005】虚拟内存,我也就能写写这种模拟题了
  6. 一个优秀数据分析师的准则
  7. SCOM监控APC-UPS不间断电源设备
  8. login RPi via serial port
  9. Visual Studio Code下载安装教程
  10. 数据库(教务管理系统)
  11. Linux创建和删除目录
  12. 英雄联盟(LOL)外挂原理(仅供学术交流)
  13. LC EDA 学习笔记
  14. 设计原则与思想:设计原则12讲
  15. 2016.04.03软件更新公告
  16. python求峰面积_python---matplotlib
  17. oracle12c命令行安装grid,oracle12c-RAC安装部署之GRID安装-grid设置
  18. 解决Qt6 Android 开发中 Qtkits 前有黄色感叹号问题
  19. 微信小程序云开发:基本介绍及云端数据库的使用
  20. Three.js学习笔记-Lights(灯光)

热门文章

  1. 基本ACL与高级ACL
  2. Binder通信机制介绍
  3. QT STUDY 模型-视图-控制器
  4. 设置程序无label
  5. 根据坐标获取地图经纬度
  6. 初探 Unix 操作系统
  7. xfs文件系统下扩展lvm卷组
  8. 1-编程的基本条件和起步
  9. poj-1062-昂贵的聘礼
  10. 查询出的数据记录字段要与实体类中的属性名一致