目录

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. C指针与二维数组

    先贴上完整的代码: #include<stdio.h> int main(int argc, char *argv[]){ int a[3] [5]={1,2,3,4,5,6,7,8,9, ...

  2. 2017-2018 ACM-ICPC Northern Eurasia(A.Archery Tournament)

    题目链接:https://vjudge.net/problem/Gym-101630A 题意: n个事件,t=1 代表增加一个圆心为(x,y),半径为 abs(y)的靶子,t=2,代表射击的坐标为(x ...

  3. C语言宏的使用

    使用条件宏进行条件编译 譬如,对于同一份代码,我想编译出两个不同的版本,在其中一个版本中去掉某一部分功能, 这时可以通过条件宏判断是否编译,例: 如果不使用条件宏进行控制,想编译两个不同版本的程序,就 ...

  4. java例题_24 逆向输入数字

    1 /*24 [程序 24 根据输入求输出] 2 题目:给一个不多于 5 位的正整数,要求:一.求它是几位数,二.逆序打印出各位数字. 3 */ 4 5 /*分析 6 * 首先从键盘得到一个正整数,不 ...

  5. irace package -- 参数调优神器

    目录 1. irace 是什么 2. 安装 irace 3. irace 的运行机制 4. irace 的配置环境 4.1. parameters 4.2. target algorithm runn ...

  6. SpringBoot中整合Redis、Ehcache使用配置切换 并且整合到Shiro中

    在SpringBoot中Shiro缓存使用Redis.Ehcache实现的两种方式实例 SpringBoot 中配置redis作为session 缓存器. 让shiro引用 本文是建立在你是使用这sh ...

  7. java进阶(38)--线程安全

    文档目录: 一.概念 二.解决方案 三.举例说明 ---------------------------------------分割线:正文------------------------------ ...

  8. 前端开发面试题 — html篇

    正值跳槽的金三银四月,在四月的中旬之际,博主为大家整理了几篇前端面试题,希望不会太迟 1.Doctype作用?标准模式与兼容模式各有什么区别? (1)<!DOCTYPE> 声明位于HTML ...

  9. 11. man page,info page

    Linux系统中的命令可分为内部命令和外部命令.内部命令,又称为内建命令(builtin).怎么区分内部命令和外部命令了? 输入man bash命令,就可查看所有的内部命令. 如何查看命令使用方法 内 ...

  10. 由奶茶店突发奇想开始了Java设计模式:享元模式

    目录 定义 意图 主要解决问题 何时使用 优缺点 结构 奶茶摊位的例子 奶茶店的例子 在什么情况下使用享元模式 定义 享元模式是对象的结构模式,享元模式以共享的方式高效的支持大量的细粒度对象,主要用于 ...