学习记录 HashMap中负载因子的意义是什么?

HashMap具有两个重要属性:

sizeload factor

HashMap的实例具有两个影响其性能的参数:初始容量(0.75f)和负载因子(load factor)。
容量是哈希表中存储桶的数量,初始容量只是创建哈希表时的容量。
负载因子是在自动增加其哈希表容量之前允许哈希表获得的满度的度量。
当哈希表中的条目数超过负载因子和当前容量的乘积时,哈希表将被重新哈希
(即,内部数据结构将被重建),因此哈希表的存储桶数大约为两倍。通常,默认负载因子(.75)在时间和空间成本之间提供了一个很好的折中方案。
较高的值会减少空间开销,但会增加查找成本(在HashMap类的大多数操作中都得到体现,
包括get和put)。设置映射表的初始容量时,应考虑映射中的预期条目数及其负载因子,
以最大程度地减少重新哈希操作的数量。如果初始容量大于最大条目数除以负载因子,
则将不会进行任何哈希操作。与所有性能优化一样,最好避免过早地进行优化(例如,没有关于瓶颈所在的硬数据)。

HashMap文档:

1.基于哈希表的Map接口的实现。此实现提供所有可选的映射操作,并允许 空值和空键。(HashMap 类与Hashtable大致等效,不同之处在于它是不同步的,并且允许为null。)此类不保证映射的顺序。特别是,它不能保证顺序会随着时间的推移保持恒定。

2.假设哈希函数将元素正确分散在存储桶中,则此实现为基本操作(get和put)提供恒定时间的性能。集合视图上的迭代所需的时间与HashMap实例的“容量” (存储桶数)及其大小(键-值映射数)成正比 。因此,如果迭代性能很重要,则不要将初始容量设置得过高(或负载因子过低),这一点非常重要。

3.HashMap的实例具有两个影响其性能的参数:初始容量和负载因子。的 容量是在哈希表中桶的数量,和初始容量是简单地在创建哈希表中的时间的能力。该 负载系数是的哈希表是如何充分允许获得之前它的容量自动增加的措施。当哈希表中的条目数超过负载因子和当前容量的乘积时,哈希表将被重新哈希(即,内部数据结构将被重建),因此哈希表的存储桶数大约为两倍。

4.通常,默认负载因子(.75)在时间和空间成本之间提供了一个很好的折衷方案。较高的值会减少空间开销,但会增加查找成本(在HashMap类的大多数操作中都得到体现 ,包括get和put)。设置映射表的初始容量时,应考虑映射中的预期条目数及其负载因子,以最大程度地减少重新哈希操作的数量。如果初始容量大于最大条目数除以负载因子,则将不会进行任何哈希操作。

5.如果要将许多映射存储在HashMap实例中,则创建具有足够大容量的映射将比使它根据需要增长表的自动重新哈希处理更有效地存储映射。

6.请注意,此实现未同步。 如果多个线程同时访问哈希映射,并且至少有一个线程在结构上修改该映射,则必须在外部进行同步。(结构修改是添加或删除一个或多个映射的任何操作;仅更改与实例已经包含的键相关联的值不是结构修改。)通常通过在自然封装了地图的某个对象上进行同步来实现。 。如果不存在这样的对象,则应使用Collections.synchronizedMap 方法“包装”地图 。最好在创建时完成此操作,以防止意外不同步地访问Map:
Map m = Collections.synchronizedMap(new HashMap(…));

7.由此类的所有“集合视图方法”返回的迭代器都是快速失败的:如果在创建迭代器后的任何时间以任何方式对地图进行结构修改,除非通过迭代器自己的 remove方法,否则迭代器将抛出 ConcurrentModificationException。因此,面对并发修改,迭代器会快速干净地失败,而不会在未来的不确定时间内冒任意,不确定的行为的风险。

8.请注意,迭代器的快速失败行为无法得到保证,因为通常来说,在存在不同步的并发修改的情况下,不可能做出任何严格的保证。快速失败的迭代器会尽最大努力抛出ConcurrentModificationException。因此,编写依赖于此异常的程序以确保其正确性是错误的:迭代器的快速失败行为应仅用于检测错误。

什么是HashMap?

HashMap 是一个用于存储Key-Value 键值对的集合,每一个键值对也叫做Entry。
这些个Entry 分散存储在一个数组当中,这个数组就是HashMap 的主干。
HashMap 数组每一个元素的初始值都是Null。

如图一:

  1. Put 方法的原理
    调用Put方法的时候发生了什么呢?
    比如调用 hashMap.put(“apple”, 0) ,插入一个Key为“apple”的元素。这时候我们需要利用一个哈希函数来确定Entry的插入位置(index):
    index = Hash(“apple”)
    假定最后计算出的index是2,那么结果如下:
    如图二:

但是,因为HashMap的长度是有限的,当插入的Entry越来越多时,再完美的Hash函数也难免会出现index冲突的情况。比如下面这样:
如图三:

这时候该怎么办呢?我们可以利用链表来解决。
HashMap数组的每一个元素不止是一个Entry对象,也是一个链表的头节点。每一个Entry对象通过Next指针指向它的下一个Entry节点。当新来的Entry映射到冲突的数组位置时,只需要插入到对应的链表即可:
如图四:

新来的Entry节点插入链表时,使用的是“头插法。

  1. Get方法的原理
    使用Get方法根据Key来查找Value的时候,发生了什么呢?
    首先会把输入的Key做一次Hash映射,得到对应的index:
    index = Hash(“apple”)
    由于刚才所说的Hash冲突,同一个位置有可能匹配到多个Entry,这时候就需要顺着对应链表的头节点,一个一个向下来查找。假设我们要查找的Key是“apple”:
    如图五:

第一步,我们查看的是头节点Entry6,Entry6的Key是banana,显然不是我们要找的结果。
第二步,我们查看的是Next节点Entry1,Entry1的Key是apple,正是我们要找的结果。
之所以把Entry6放在头节点,是因为HashMap的发明者认为,后插入的Entry被查找的可能性更大。

  1. HashMap的初始长度
    初始长度为16,且每次自动扩容或者手动初始化的时候必须是2的幂。
    如何进行位运算呢?有如下的公式(Length是HashMap的长度):
    之前说过,从Key映射到HashMap数组的对应位置,会用到一个Hash函数:
    index = Hash(“apple”)
    如何实现一个尽量均匀分布的Hash函数呢?我们通过利用Key的HashCode值来做某种运算。
    index = HashCode(Key) & (Length - 1)
    下面我们以值为“book”的Key来演示整个过程:

计算book的hashcode,结果为十进制的3029737,二进制的101110001110101110 1001。
假定HashMap长度是默认的16,计算Length-1的结果为十进制的15,二进制的1111。
把以上两个结果做与运算,101110001110101110 1001 & 1111 = 1001,
十进制是9,所以 index=9。

可以说,Hash算法最终得到的index结果,完全取决于Key的Hashcode值的最后几位。
这里的位运算其实是一种快速取模算法。

HashMap 的size为什么必须是2的幂?。这是因为2的幂用二进制表示时所有位都为1,例如16-1=15 的二进制就是1111B。我们说了Hash算法是为了让hash 的分布变得均匀。其实我们可以把1111看成四个通道,表示跟1111 做&运算后分布是均匀的。假如默认长度取10,二进制表示为1010,这样就相当于有两个通道是关闭的,所以计算出来的索引重复的几率比较大。

与君共勉

我要一步一步往上爬
在最高点乘着叶片往前飞
任风吹干流过的泪和汗
我要一步一步往上爬
等待阳光静静看着它的脸
小小的天有大大的梦想
我有属于我的天
任风吹干流过的泪和汗
总有一天我有属于我的天

HashMap中负载因子的意义是什么?相关推荐

  1. 原创 | 我说我了解集合类,面试官竟然问我为啥HashMap的负载因子不设置成1!?...

    △Hollis, 一个对Coding有着独特追求的人△ 这是Hollis的第 254篇原创分享 作者 l Hollis 来源 l Hollis(ID:hollischuang) 在Java基础中,集合 ...

  2. 我说我了解集合类,面试官竟然问我为啥HashMap的负载因子不设置成1!?

    在Java基础中,集合类是很关键的一块知识点,也是日常开发的时候经常会用到的.比如List.Map这些在代码中也是很常见的. 个人认为,关于HashMap的实现,JDK的工程师其实是做了很多优化的,要 ...

  3. HashMap的负载因子初始值为什么是0.75?这篇文章以最通俗的方式告诉你答案

    之前写过一篇专门介绍HashMap的文章,反响很不错,不过在留言区问的最多的问题就是HashMap的负载因子初始值为什么是0.75,私下又好好地研究了一番,总结了这篇文章. 本篇文章基于JDK1.8, ...

  4. HashMap的负载因子为什么默认是0.75

    作用 负载因子是和扩容机制有关的,意思是如果当前容器的容量,达到了我们设定的最大值,就要开始执行扩容操作.比如说当前的容器容量是16,负载因子是0.75,16*0.75=12,也就是说,当容量达到了1 ...

  5. 哈希 :哈希冲突、负载因子、哈希函数、哈希表、哈希桶

    文章目录 哈希 哈希(散列)函数 常见的哈希函数 字符串哈希函数 哈希冲突 闭散列(开放地址法) 开散列(链地址法/拉链法) 负载因子以及增容 对于闭散列 对于开散列结构 具体实现 哈希表(闭散列) ...

  6. HashMap负载因子

    下面是HashMap的一个构造函数,两个参数initialCapacity,loadFactor 这关系HashMap的迭代性能. 1 /** 2 * Constructs an empty < ...

  7. HashMap与加载因子/负载因子loadFactor关系

    HashMap以<key,value>的方式存放数据,存储在数组中.通过开散列方法解决冲突,数组中存放的Entry作为单向链表的表头. Entry的源码如下: static class E ...

  8. 什么是加载因子/负载因子/装载因子

    什么是加载因子(负载因子/装载因子)? 用于表示哈希表中元素填满的程度. 冲突的机会越大,则查找的成本越高.反之,查找的成本越低,从而查找的时间越少. HashMap中的加载因子 ①new HashM ...

  9. HashMap 的性能因子

    参考目录: 1. HashMap 散列初体验 2. 为什么HashMap 常用String 对象作key 3. HashMap 原理 4.自定义 hashCode() 5.HashMap 的性能因子 ...

最新文章

  1. 计网 - 流和缓冲区:缓冲区的 flip 是怎么回事?
  2. 笔记-信息系统开发基础-信息系统生命周期
  3. 520 钻石争霸赛 7-6 矩阵列平移(循环)
  4. CWinThread
  5. 14岁考入北大少年班,如今节衣缩食上课穿胶鞋,却慷慨资助贫困生
  6. 谷歌YouTube算法团队:视频质量评价的集成池化方法
  7. PHP收费事件导致用户流失,PHP秒杀系统方案(解决大流量,高并发)
  8. 微课|中学生可以这样学Python(例4.2):打印九九乘法表
  9. Shell脚本编程之(六)循环
  10. CSDN如何修改id号
  11. SM2算法全套(基于GMSSL)
  12. 止步智能手机,网易的移动互联网冷静剂
  13. 简单使用Jconsole
  14. DS1302时钟芯片(SPI协议)
  15. HTTP 417 错误 – 预期结果失败 (Expectation failed)
  16. allegro更新铜皮方法和快捷键
  17. 如何在ubuntu上解压压缩包
  18. 云计算时代的域名解析
  19. 三种网络模型(OSI七层参考模型、TCP/IP参考模型、五层参模型)
  20. 读书笔记之:《心流 最优体验心理学》 米哈里·契克森米哈赖 第一章、第二章

热门文章

  1. qq人脸更换_如何画出合理自然的漫画人脸?
  2. AndroidWeekly-2019年03月18日-2019年03月24日
  3. 名词解释第五十六讲:矿工费
  4. tensorflow的sess.run的参数执行顺序
  5. Android资源图片读取机制
  6. 真人视频秒变高清动漫脸,数十种“滤镜”可选,在线可玩
  7. win7 64位 系统中“打开或关闭Windows功能”列表空白
  8. 【动态规划】聪明伶俐的香穗子
  9. 《中国互联网络发展状况统计报告》:网民规模达6.88亿
  10. 独家 | 环境大数据的应用案例及前景