对于 HashMap 及其子类而言,它们采用 Hash 算法来决定集合中元素的存储位置。当系统开始初始化 HashMap 时,系统会创建一个长度为 capacity 的 Entry 数组,这个数组里可以存储元素的位置被称为“桶(bucket)”,每个 bucket 都有其指定索引,系统可以根据其索引快速访问该 bucket 里存储的元素。

无论何时,HashMap 的每个“桶”只存储一个元素(也就是一个 Entry),由于 Entry 对象可以包含一个引用变量(就是 Entry 构造器的的最后一个参数)用于指向下一个 Entry,因此可能出现的情况是:HashMap 的 bucket 中只有一个 Entry,但这个 Entry 指向另一个 Entry ——这就形成了一个 Entry 链。如图 1 所示:

图 1. HashMap 的存储示意

HashMap 的读取实现

当 HashMap 的每个 bucket 里存储的 Entry 只是单个 Entry ——也就是没有通过指针产生 Entry 链时,此时的 HashMap 具有最好的性能:当程序通过 key 取出对应 value 时,系统只要先计算出该 key 的 hashCode() 返回值,在根据该 hashCode 返回值找出该 key 在 table 数组中的索引,然后取出该索引处的 Entry,最后返回该 key 对应的 value 即可。看 HashMap 类的 get(K key) 方法代码:

Java代码

  1. public V get(Object key)
  2. {
  3. // 如果 key 是 null,调用 getForNullKey 取出对应的 value
  4. if (key == null)
  5. return getForNullKey();
  6. // 根据该 key 的 hashCode 值计算它的 hash 码
  7. int hash = hash(key.hashCode());
  8. // 直接取出 table 数组中指定索引处的值,
  9. for (Entry<K,V> e = table[indexFor(hash, table.length)];
  10. e != null;
  11. // 搜索该 Entry 链的下一个 Entr
  12. e = e.next)         // ①
  13. {
  14. Object k;
  15. // 如果该 Entry 的 key 与被搜索 key 相同
  16. if (e.hash == hash && ((k = e.key) == key
  17. || key.equals(k)))
  18. return e.value;
  19. }
  20. return null;
  21. }

从上面代码中可以看出,如果 HashMap 的每个 bucket 里只有一个 Entry 时,HashMap 可以根据索引、快速地取出该 bucket 里的 Entry;在发生“Hash 冲突”的情况下,单个 bucket 里存储的不是一个 Entry,而是一个 Entry 链,系统只能必须按顺序遍历每个 Entry,直到找到想搜索的 Entry 为止——如果恰好要搜索的 Entry 位于该 Entry 链的最末端(该 Entry 是最早放入该 bucket 中),那系统必须循环到最后才能找到该元素。

归纳起来简单地说,HashMap 在底层将 key-value 当成一个整体进行处理,这个整体就是一个 Entry 对象。HashMap 底层采用一个 Entry[] 数组来保存所有的 key-value 对,当需要存储一个 Entry 对象时,会根据 Hash 算法来决定其存储位置;当需要取出一个 Entry 时,也会根据 Hash 算法找到其存储位置,直接取出该 Entry。由此可见:HashMap 之所以能快速存、取它所包含的 Entry,完全类似于现实生活中母亲从小教我们的:不同的东西要放在不同的位置,需要时才能快速找到它。

当创建 HashMap 时,有一个默认的负载因子(load factor),其默认值为 0.75,这是时间和空间成本上一种折衷:增大负载因子可以减少 Hash 表(就是那个 Entry 数组)所占用的内存空间,但会增加查询数据的时间开销,而查询是最频繁的的操作(HashMap 的 get() 与 put() 方法都要用到查询);减小负载因子会提高数据查询的性能,但会增加 Hash 表所占用的内存空间。

掌握了上面知识之后,我们可以在创建 HashMap 时根据实际需要适当地调整 load factor 的值;如果程序比较关心空间开销、内存比较紧张,可以适当地增加负载因子;如果程序比较关心时间开销,内存比较宽裕则可以适当的减少负载因子。通常情况下,程序员无需改变负载因子的值。

如果开始就知道 HashMap 会保存多个 key-value 对,可以在创建时就使用较大的初始化容量,如果 HashMap 中 Entry 的数量一直不会超过极限容量(capacity * load factor),HashMap 就无需调用 resize() 方法重新分配 table 数组,从而保证较好的性能。当然,开始就将初始容量设置太高可能会浪费空间(系统需要创建一个长度为 capacity 的 Entry 数组),因此创建 HashMap 时初始化容量设置也需要小心对待。

HashMap中的bucket介绍相关推荐

  1. 03_MyBatis基本查询,mapper文件的定义,测试代码的编写,resultMap配置返回值,sql片段配置,select标签标签中的内容介绍,配置使用二级缓存,使用别名的数据类型,条件查询ma

     1 PersonTestMapper.xml中的内容如下: <?xmlversion="1.0"encoding="UTF-8"?> < ...

  2. hashmap中的key是有序的么_HashMap?面试?我是谁?我在哪

    (给ImportNew加星标,提高Java技能) 转自:卓庆森 https://www.cnblogs.com/zhuoqingsen/p/8577646.html 现在是晚上11点了,学校屠猪馆的自 ...

  3. HashMap中傻傻分不清楚的那些概念

    转载自 HashMap中傻傻分不清楚的那些概念 很多人在通过阅读源码的方式学习Java,这是个很好的方式.而JDK的源码自然是首选.在JDK的众多类中,我觉得HashMap及其相关的类是设计的比较好的 ...

  4. 【java基础 12】HashMap中是如何形成环形链表的?

    导读:经过前面的博客总结,可以知道的是,HashMap是有一个一维数组和一个链表组成,从而得知,在解决冲突问题时,hashmap选择的是链地址法.为什么HashMap会用一个数组这链表组成,当时给出的 ...

  5. 为什么HashMap中链表转红黑树的阀值是8?

    在JDK1.8以后,HashMap中引入红黑树,主要原因为: 当一个桶(Bucket)中的元素过度填充时,链表的查找效率将会大大下降,因此在适当的时候,转换链表为红黑树,可以在桶过度填充时提高查询效率 ...

  6. HashMap 中那些精妙绝伦的设计

     点击上方关注 "终端研发部" 设为"星标",和你一起掌握更多数据库知识 一.HashMap构造器 HashMap总共给我们提供了三个构造器来创建HashMap ...

  7. HashMap 中 hash 冲突的解决方法及原理分析

    我们最先衰老的不是容貌,而是不顾一切的闯劲.有时候,要敢于背上超出自己预料的包袱,真的努力后,你会发现自己要比想象的优秀很多. HashMap冲突的解决方法比较考验一个开发者解决问题的能力. 在Jav ...

  8. HashMap中的位运算

    Java 8 中 HashMap 的实现使用了很多位操作来进行优化.本文将详细介绍每种位操作优化的原理及作用. Java 中的位运算 位操作包含:与.或.非.异或 移位操作包含:左移.右移.无符号右移 ...

  9. Java中List集合介绍(炒鸡详细呦)

    Java中List集合介绍 文章目录 Java中List集合介绍 1,Java集合介绍 2,List介绍 2.1 ArrayList集合 2.2 LinkedList集合 3,List常用方法 3.1 ...

最新文章

  1. python抓包工具_「docker实战篇」python的docker爬虫技术-fiddler抓包软件详细配置(七)...
  2. 微信小程序WebSocket实现聊天对话功能完整源码
  3. 四十三、文件存储空间管理
  4. Java学习之while语句
  5. 台达变频器s1参数设置_【智】台达变频器计数输入功能接线和参数设置详解
  6. 王道计算机考研 数据结构 (查找-上)
  7. MTM:matlab实现2参数解析
  8. 4.0.13 mysql 注入_Windows2000下整合Mysql4.0.13与Tomcat4.1.24搭建Jsp环境
  9. mysql workbench 监控_mysql 使用workbench工具,表状态为read only的解决方法
  10. 常量(const)和只读变量(readonly)
  11. python爬虫获取url_Python爬虫如何获取页面内所有URL链接?本文详解
  12. 10038 mysql,关于MySql 10038错误的完美解决方法(三种)
  13. 开发了一套python的七牛sdk
  14. 卫星导航开源代码汇总
  15. 16种床上动作的内涵图,你都看懂了吗?
  16. 学习python表情包_我用Python一键保存了半佛老师所有的骚气表情包
  17. table 点击文字按钮预览图片
  18. Matlab使用中遇到的一些脑残问题。
  19. android开发-验证邮箱输入是否合法
  20. Edge 安装 CSDN 浏览器助手

热门文章

  1. PCL点云库(Point Cloud Library)简介
  2. 小笨狗的编程感悟(序言)
  3. android中文乱码的解决办法
  4. HCIE 面试资料-BFD/NSF/NSR/NTP
  5. taobao.trade.fullinfo.get( 获取单笔交易的详细信息 )、淘宝店铺卖出订单详情接口,淘宝店铺订单明文接口,淘宝店铺订单解密接口
  6. 读《史蒂夫•乔布斯传》(二)
  7. anaconda使用心得
  8. 公司监控显示无网络连接服务器,监控显示无网络视频什么原因
  9. TTL,CMOS,LVTTL,LVCMOS电平标准
  10. 用Python写个桌面挂件,手把手带你做只桌面宠物~