目录

content

HashMap 的数据结构:

  • 数组 + 链表(Java7 之前包括 Java7)
  • 数组 + 链表 + 红黑树(从 Java8 开始)

PS:这里的《红黑树》与链表都是链式结构。

HashMap 内部维护了一个数组,数组中存放链表的链首或红黑树的树根。

当链表长度超过 8 时,链表就转换为红黑树,利用红黑树快速增删改查的特点提高 HashMap 的性能;在红黑树结点数量小于 6 时,红黑树转变为链表。

下面分别为上面两种数据结构的图示:


【定位算法】

增加、查找、删除等操作都需要先定位到 table 数组的某个索引处。

定位算法为三步:取 key 的 hashCode 值、高位运算、取模运算得到索引位置。(代码如下)

static final int hash(Object key) {
int h;
// h = key.hashCode() 第一步 取 hashCode 值
// h ^ (h >>> 16) 第二步 高位参与运算 Java8 优化了高位算法,优化原理忽略
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
} // java7 中这是一个单独的方法,java8 没有了这个方法但是原理依旧
static int indexFor(int h, int length) {
return h & (length-1); // hash(key) & (length-1) 第三步 取模
}

取模运算h & (length -1)的结果最大值为 length -1,不会出现数组下标越界的情况。

为什么要做高位运算?

如果 hashCode 值都大于 length,而且这些 hashCode 的低位变化不大,就会出现很多冲突,举个例子:

  • 假设数组的初始化容量为 16(10000),则 length -1 位 15(1111)。
  • 假设有几个对象的 hashCode 分别为 1100 10010、1110 10010、11101 10010,如果不做高位运算,直接使用它们做取模运算的结果将是一致的。

如果所有元素中多数元素属于这种情况,将会导致元素分布不均匀,而对 hashCode 进行高位运算能解决这个问题,使高位对低位造成影响改变低位的值,从而变相地使高位也参与运算。

append

【Q】负载因子与性能的关系

负载因子默认值为0.75,意味着当数组实际填充量占比达到3/4时就该扩容了。

负载因子越大,扩容次数必然越少,数组的长度越小,减少了空间开销;这就会导致 hash 碰撞越多,增加查询成本。

默认值0.75在时间和空间成本上寻求一种折衷。


【Q】为什么要扩容

因为随着元素量的增大,hash 碰撞的概率越来越大,虽然使用链地址法能够解决存储问题,但是长长的链表会让 HashMap 失去快速检索的优势,而扩容能解决这个问题。

HashMap 的数据结构的更多相关文章

  1. Java中HashMap的数据结构

    类声明: 概述: 线程不安全: <Key, Value>两者都可以为null: 不保证映射的顺序,特别是它不保证该顺序恒久不变: HashMap使用Iterator: HashMap中ha ...

  2. jdk1.8源码解析:HashMap底层数据结构之链表转红黑树的具体时机

    本文从三个部分去探究HashMap的链表转红黑树的具体时机: 一.从HashMap中有关“链表转红黑树”阈值的声明: 二.[重点]解析HashMap.put(K key, V value)的源码: 三 ...

  3. HashMap底层数据结构详解

    一.HashMap底层数据结构 JDK1.7及之前:数组+链表 JDK1.8:数组+链表+红黑树 关于HashMap基本的大家都知道,但是为什么数组的长度必须是2的指数次幂,为什么HashMap的加载 ...

  4. [转]java 的HashMap底层数据结构

    java 的HashMap底层数据结构   HashMap也是我们使用非常多的Collection,它是基于哈希表的 Map 接口的实现,以key-value的形式存在.在HashMap中,key-v ...

  5. java 的HashMap底层数据结构

    HashMap也是我们使用非常多的Collection,它是基于哈希表的 Map 接口的实现,以key-value的形式存在.在HashMap中,key-value总是会当做一个整体来处理,系统会根据 ...

  6. HashMap底层数据结构和算法解析

    1.Hash Map的数据结构? A:哈希表结构(链表散列:数组+链表)实现,结合数组和链表的优点.当链表长度超过8时,链表转换为红黑树. transient Node<K,V>[] ta ...

  7. hashMap的数据结构

    HashMap底层实现还是数组,只是数组的每一项都是一条链.

  8. jdk1.8 HashMap底层数据结构:深入解析为什么jdk1.8 HashMap的容量一定要是2的n次幂

    前言 1.本文根据jdk1.8源码来分析HashMap的容量取值问题: 2.本文有做 jdk1.8 HashMap.resize()扩容方法的源码解析:见下文“一.3.扩容:同样需要保证扩容后的容量是 ...

  9. 探索HashMap实现原理及其在jdk8数据结构的改进

    因为网上已经太多的关于HashMap的相关文章了,为了避免大量重复,又由于网上关于java8的HashMap的相关文章比较少,至少我没有找到比较详细的.所以才有了本文. 本文主要的内容: 1.Hash ...

随机推荐

  1. nginx使用-2(模块和日志)

    默认官方模块 1.1.Gzip压缩 压缩文件,使文件变小,传输更快了.目前市场上大部分浏览器是支持GZIP的.IE6以下支持不好,会出现乱码情况. 官方文档:http://nginx.org/en/d ...

  2. classLoader动态加载技术

    //加载器,apkPath为包含dex文件的.apk或jar路径,dexPath是优化后的dex文件路径,第三个表示libraryPath表示Native库的路径,最后是父类加载器 DexClassL ...

  3. Linux入门视频笔记三(常用工具集)

    一.全局变量(Linux中的全局变量指在整个系统中都能用的变量) 1.USER:当前登录系统的用户的用户名 2.HOME:当前用户的主目录 cd $HOME 或 cd ~可以进入用户主目录 3.PAT ...

  4. ABP 适用性改造 - 精简 ABP CLI 生成的项目结构

    Overview 不管是公司或者个人都会有不同的开发习惯,通过建立项目模板,既可以使开发人员聚焦于业务功能的开发,也可以在一定程度上统一不同开发人员之间的开发风格.在使用 ABP 框架的过程中,对于 ...

  5. 一些DevTools的小技巧-让你不止会console.log()

    转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. 原文参考:https://www.sitepoint.com/beyond-console-log-leve ...

  6. Ubuntu20.04linux内核(5.4.0版本)编译准备与实现过程-编译前准备(1)

    最近项目也和linux kernel技术有关,调试内核和内核模块.修改内核源码,是学习内核的重要技术手段之一.应用这些技术时,都有一本基本的要求,那就是编译内核.因此,在分析内核调试技术之前,本随笔给 ...

  7. 简易计算器实现:while循环+switch语句

    个人练习: 写一个计算器,要求实现加减乘除功能,并且能循环接收新的数据,通过用户交互实现(即Scanner对象) 用到了 while循环 switch语句,实现了数据的循环输入并计算!!!!妙啊!!! ...

  8. Markdown部分用法总结

    1.Markdown数学公式&符号 2.Cmd Markdown 公式指导手册

  9. 带你全面认识CMMI V2.0(一)

    新发布的CMMI V2.0在方法论和方法上都提出了一些战略上的变化和改进.这些更新提供了新的要求.历史标准的演进以及以往实践的延续. CMMI V2.0和CMMI V1.3的变化 CMMIV2.0的定 ...

  10. OOUnit4Summary

    一.前三次作业的架构设计 前言 第四单元以uml建模语言为背景,让我们通过已有的模型架构,设计实现类图(顺序图,状态图)解析器:在理解uml整体架构体系的基础上,读懂并熟练运用官方的给的代码,设计有层 ...