讲讲HashMap?

源码解析

final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
//辅助变量
Node<K,V>[] tab; Node<K,V> p; int n, i;
//如果当前tabe数组是null,数量是0的话
if ((tab = table) == null || (n = tab.length) == 0)
//执行扩容方法resize()
//初始化数组默认大小是16
n = (tab = resize()).length;
//通过hash与运算获得数组索引位置,该位置是null
if ((p = tab[i = (n - 1) & hash]) == null)
//创建新Node对象
tab[i] = newNode(hash, key, value, null);
else {//该索引位置不为null
Node<K,V> e; K k;
//当前table索引hash和新的索引hash相同 &&
//(当前table节点的key和新key是同一对象 || equals为真)
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;
//如果当前table的node已是红黑树就按红黑树处理
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
else {
//如果节点是后面是链表就遍历比较
for (int binCount = 0; ; ++binCount) {
//遍历整个链表结束,也没有和新的key相同的就添加链表后面新创建node
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
//加入后判断当前的链表个数是否已经达到8个,如果达到就进行红黑树转换
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
//提示:
//treeifyBin里如果table为null或者大小小于64,暂时不会转化为红黑树
//而是进行扩容。
//if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
treeifyBin(tab, hash);
break;
}
//发现相同就break结束遍历
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value; //替换原有的值,直接结束
afterNodeAccess(e);
return oldValue;
}
}
++modCount;
//每增加node,Size++
//如果数量大于临界值,就进行扩容
//threshold=table大小(默认16)*负载因子(默认0.75)
//12>24>>48
if (++size > threshold)
//扩容成2倍增长16->32->64
resize();
afterNodeInsertion(evict);
return null;
}

简述

Jdk1.7 数组+链表

Jdk1.8 数组+链表+红黑树

hashMap 默认数组大小16,负载因子 默认0.75, 临界值= 数组大小*负载因子。

  1. 首先将key进行hash算法,key的hashCode右移16位并进行异或运算。
  2. 如果table是null ,先初始化数组默认大小是16
  3. 通过hash的与运算获得当前table索引位置,如果索引位置内容是null则创建新Node节点对象
  4. 如果当前table索引位置里内容不为null,则寻找相同key直接修改值,分三种情况
    1. 当前table索引的对象hash是否与新hash相同并且当前table位置对象key是否和新key相同
    2. 如果当前table索引的对象已是TreeNode(红黑树)就进行遍历树方式查找
    3. 如果是链表则遍历链表查找,如果遍历完也没找到就往链表尾部加入并创建新Node,在判断当前大小是否大于等于8,如果大于就进行红黑树转化。执行红黑树转化方法时有个条件,如果数组大小小于64则还是进行扩容操作。
  5. 当前Size数组大小和threshold(临界值)比较,如果size大于threshold则进行扩容(2倍增长),

问题

JDK 1.8中对hash算法和寻址算法是如何优化的?

//hash算法优化
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
//(n - 1) & hash 寻址算法优化
if ((p = tab[i = (n - 1) & hash]) == null)

配合来说,put键值时,肯定涉及数组长度的取模运算,但是在计算机上面(n - 1) & hash位运算效率高于普通的除法取余。关键这个n(hashmap长度)通常会很小,但是hash值是32位的,因此(n-1)大概率高位补零,由于与运算是只有两个数字都是1结果才为1,其他情况均为0,因此hash值的高16位永远起不到作用,这样就大大的增加了寻址冲突概率,除非数组长度很大,撑满整个32位最好都为1,才不会有冲突,但一般不可能很长,所以通过hash算法的优化(h = key.hashCode()) ^ (h >>> 16) 这个公式完美的让hash值高16位与低16位融合,保留高低16位的特征。再跟(n-1)做与运算,hash冲突的概率就降低了!

深度解析HashMap的更多相关文章

  1. 深度解析HashMap底层实现架构

    摘要:分析Map接口的详细使用以及HashMap的底层是如何实现的? 本文分享自华为云社区<[图文并茂]深度解析HashMap高频面试及底层实现结构![奔跑吧!JAVA]>,原文作者:灰小 ...

  2. 深度解析HashMap集合底层原理

    目录 前置知识 ==和equals的区别 为什么要重写equals和HashCode 时间复杂度 (不带符号右移) >>> ^异或运算 &(与运算) 位移操作:1<&l ...

  3. 源码深度解析SpringMvc请求运行机制(转)

    源码深度解析SpringMvc请求运行机制 本文依赖的是springmvc4.0.5.RELEASE,通过源码深度解析了解springMvc的请求运行机制.通过源码我们可以知道从客户端发送一个URL请 ...

  4. mybatis 3.x源码深度解析与最佳实践(最完整原创)

    mybatis 3.x源码深度解析与最佳实践 1 环境准备 1.1 mybatis介绍以及框架源码的学习目标 1.2 本系列源码解析的方式 1.3 环境搭建 1.4 从Hello World开始 2 ...

  5. Flink 源码解析 —— 深度解析 Flink 是如何管理好内存的?

    前言 如今,许多用于分析大型数据集的开源系统都是用 Java 或者是基于 JVM 的编程语言实现的.最着名的例子是 Apache Hadoop,还有较新的框架,如 Apache Spark.Apach ...

  6. Spring源码深度解析之Spring MVC

    Spring源码深度解析之Spring MVC Spring框架提供了构建Web应用程序的全功能MVC模块.通过策略接口,Spring框架是高度可配置的,而且支持多种视图技术,例如JavaServer ...

  7. [WebKit内核] JavaScript引擎深度解析--基础篇(一)字节码生成及语法树的构建详情分析

    [WebKit内核] JavaScript引擎深度解析--基础篇(一)字节码生成及语法树的构建详情分析 标签: webkit内核JavaScriptCore 2015-03-26 23:26 2285 ...

  8. 第37课 深度解析QMap与QHash

    1. QMap深度解析 (1)QMap是一个以升序键顺序存储键值对的数据结构 ①QMap原型为 class QMap<K, T>模板 ②QMap中的键值对根据Key进行了排序 ③QMap中 ...

  9. Deep Learning模型之:CNN卷积神经网络(一)深度解析CNN

    http://m.blog.csdn.net/blog/wu010555688/24487301 本文整理了网上几位大牛的博客,详细地讲解了CNN的基础结构与核心思想,欢迎交流. [1]Deep le ...

随机推荐

  1. processon刷文件的骚操作

    https://github.com/ilikly/ProcessOnRegister用法自己看说明哈,群友亲测可用,而且也给别人用了...缺点是每轮都需要手动操作一下,并且需要俩微信号

  2. python 内置模块续(二)

    目录 python 内置模块补充 1.hashlib模块 简易使用: 高级使用: 进阶使用: 加盐处理: 校验文件一致性 2.logging日志模块 日志等级 常用处理 "四大天王" ...

  3. 【.NET 6】使用.NET 6开发minimal api以及依赖注入的实现、VS2022热重载和自动反编译功能的演示

    前言: .net 6 LTS版本发布已经有若干天了.此处做一个关于使用.net 6 开发精简版webapi(minimal api)的入门教程,以及VS2022 上面的两个强大的新技能(热重载.代码自 ...

  4. arthas 简单使用

    简介 Arthas 是Alibaba开源的Java诊断工具,深受开发者喜爱. 官网地址:https://arthas.aliyun.com/ 它可以做什么,以下功能都是直接操作线上跑着的jar包!!! ...

  5. 如何用three.js搭建处理3D园区、3D楼层、3D机房管线(机房升级版)-第九课(二)

    接着上一篇文章,<如何用webgl(three.js)搭建处理3D园区.3D楼层.3D机房管线问题(机房升级版)-第九课(一)> 继续讲解关于三维数据中心管线可视化的解决方案. 上一篇我们 ...

  6. [NOI 2014]起床困难综合症[二进制]

    背景 21 世纪,许多人得了一种奇怪的病:起床困难综合症,其临床表现为:起床难,起床后精神不佳.作为一名青春阳光好少年,atm 一直坚持与起床困难综合症作斗争.通过研究相关文献,他找到了该病的发病原因 ...

  7. Codeforces 1483F - Exam(AC 自动机)

    Codeforces 题目传送门 & 洛谷题目传送门 一道 ACAM 的 hot tea 首先建出 ACAM.考虑枚举长串,以及短串在长串中出现的最后位置 \(j\),这个复杂度显然是 \(\ ...

  8. 洛谷 P6478 - [NOI Online #2 提高组] 游戏(二项式反演+树形 dp)

    题面传送门 没错这就是我 boom0 的那场 NOIOL 的 T3 一年前,我在 NOIOL #2 的赛场上折戟沉沙,一年后,我从倒下的地方爬起. 我成功了,我不再是从前那个我了 我们首先假设 A 拥 ...

  9. Pandas 简介

    Pandas 简介 pandas 是 python 内基于 NumPy 的一种工具,主要目的是为了解决数据分析任务.Pandas 包含了大量库和一些标准的数据模型,提供了高效地操作大型数据集所需的工具 ...

  10. C语言中的各种类型所占的字节大小

    一)64位系统和32位有什么区别?  1.64bit CPU拥有更大的寻址能力,最大支持到16GB内存,而32bit只支持4G内存 2.64位CPU一次可提取64位数据,比32位提高了一倍,理论上性能 ...