HashMap的底层数据结构

  • 1.7之前是:数组+链表
    数组的元素是Map.Entiry对象
    当出现哈希碰撞的时候,使用链表解决,
    先计算出key对应的数组的下标,这个数组的这个位置上为空,直接放入,
    如果不为空而且出现哈希碰撞,就把元素添加到链表的头部的,
    new Entry(key,value,table[i]);这样这个Entry就是链表的头部了,然后放到数组的index位置上。

  • 1.8是:数组+链表+红黑树
    数组的元素是Map.Node对象继承Map.Entry包含属性有:
    当前node对象的hash值,
    当前node对象的key,
    当前node对象的下一个节点对象next,
    当前node对象的value

  • 1.8为什么使用数组+链表+红黑树?
    因为如果一个hashmap在同一个数组位置上出现hash碰撞过多,那么这个链表的长度会很长,
    插入块,但是查询因为使用的遍历所以会比较慢。

HashMap的大致结构


HashMap的关键属性有哪些?

  • 数组的默认大小16
  • 数组的最大为2的30次方
  • 扩容因子0.75
  • threshold
  • 当前数组的大小

初始大小或者扩容的数组大小为什么一定是2的次幂?

因为计算key的下标的时候使用的是:key的hashcode值 &(按位与) 数组的长度-1 ,
固定为2的次幂能保证碰撞几率小。

怎么通过key计算得到数组的下标的?

key的hashcode值 & 数组的长度-1 ;
& (与运算)

hashMap的大小是怎么计算的?

  • 有一个全局变量size,每次put的时候++,remove的时候--;

HashMap中Put方法的工作原理

  • 获取key的hashCode()值,通过位运算得到数组的下标。
  • 如果该位置上为空直接放入该数组的下标位置。
  • 如果不为空出现了碰撞,去遍历链表或者树,利用key的equal()方法是否存在相同的节点,如果相同就覆盖,不相同就放到链表的尾部。
  • 如果碰撞导致链表过长,长度大于等于8,就把链表转换成红黑树;
  • 如果数组的容量超过了总容量*负载因子的值,就要resize。

HashMap中Get方法的工作原理

bucket里的第一个节点,直接命中;
如果有冲突,则通过key.equals(k)去查找对应的entry
若为树,则在树中通过key.equals(k)查找,O(logn);
若为链表,则在链表中通过key.equals(k)查找,O(n)。

什么是哈希冲突?

哈希表在新增元素的时候首先会根据hash函数算出这个元素存放的数组的位置,
但是,有可能存在不同的key值得到相同的数组位置(两个元素的HashCode值相同),这个时候就是哈希冲突。

HashMap怎么处理哈希冲突(哈希碰撞的)

动态数组+链表(单向)的方式。

如果某个位置上的链表很长,会影响检索,JDK1.8引入了当链表的长度大于8的时候会将链表动态替换为一个红黑树,增加了搜索性能。
等于说由:数组+链表

变成了数组+链表+红黑树

HashMap中的数组什么时候扩容(rehash)

当HashMapde的长度超出了负载因子与当前容量的乘积(默认16*0.75=12)时,
通过调用resize方法重新创建一个原来HashMap大小的2倍的newTable数组,
并将原先table的元素全部移到newTable里面,重新计算hash,然后再重新根据hash分配位置,,最大扩容为2的30次方+1。
负载因子默认是:0.75

你了解重新调整HashMap大小存在什么问题吗

多线程环境下,有可能多个线程同时进行resize,在这过程中,可能产生死锁或者死循环。
具体原因不清楚。

多线程下的HashMap

HashMap是线程不安全的,所以在多线程的环境中我们需要寻找替代方案:

  • 使用Map m = Collections.synchronizedMap(new HashMap(...));实现同步
  • 使用java.util.HashTable,效率最低(因为所有的方法都是同步的,几乎被淘汰了)
  • 使用java.util.concurrent.ConcurrentHashMap,相对安全,效率高(建议使用)

Fail-Fast 机制

Fail-fast 机制是 java 集合(Collection)中的一种错误机制,
java.util.HashMap 不是线程安全的,如果在使用迭代器的过程中有其他线程修改了 map,
那么将抛出 ConcurrentModificationException,这就是所谓 fail-fast 策略
这一策略在源码中的实现是通过 modCount 也就是修改次数实现的。

与之关联的面试题:
遇到过ConcurrentModficationException(并发修改异常)异常吗?为什么会出现?如何解决?

HashMap和Hashtable的区别

  • 主要区别:Hashtable是线程安全,而HashMap则非线程安全。
  • HashMap可以使用null作为key,而Hashtable则不允许null作为key
  • HashMap的迭代器(Iterator)是fail-fast迭代器,而Hashtable的enumerator迭代器不是fail-fast的
    就是当有其它线程改变了HashMap的结构(增加或者移除元素),将会抛出ConcurrentModificationException
  • 由于Hashtable是线程安全的也是synchronized,所以在单线程环境下它比HashMap要慢

资源

小灰灰的讲解

一文搞定HashMap的实现原理和面试

HashMap工作原理及实现

必懂知识——HashMap的实现原理的更多相关文章

  1. Java面试必问之Hashmap底层实现原理(JDK1.7)

    1. 前言 Hashmap可以说是Java面试必问的,一般的面试题会问: Hashmap有哪些特性? Hashmap底层实现原理(get\put\resize) Hashmap怎么解决hash冲突? ...

  2. Java面试必问之Hashmap底层实现原理(JDK1.8)

    1. 前言 上一篇从源码方面了解了JDK1.7中Hashmap的实现原理,可以看到其源码相对还是比较简单的.本篇笔者和大家一起学习下JDK1.8下Hashmap的实现.JDK1.8中对Hashmap做 ...

  3. 面试必问:HashMap 底层实现原理

    HashMap是在面试中经常会问的一点,很多时候我们仅仅只是知道HashMap他是允许键值对都是Null,并且是非线程安全的,如果在多线程的环境下使用,是很容易出现问题的. 这是我们通常在面试中会说的 ...

  4. 2018年Fintech金融科技关键词和入行互金从业必懂知识

    2018年过去大半,诸多关键词进入眼帘: 5G,消费降级,数据裸奔,新零售,AI,物联网,云计算,合规监管,风控,割韭菜,区块链,生物识别,国民空闲时间以及金融科技. 这些词充斥着我们的生活和时间,而 ...

  5. 从代码层读懂 Java HashMap 的实现原理

    概述 Hashmap继承于AbstractMap,实现了Map.Cloneable.Java.io.Serializable接口.它的key.value都可以为null,映射不是有序的.Hashmap ...

  6. 深度剖析HashMap的数据存储实现原理(看完必懂篇)

    深度剖析HashMap的数据存储实现原理(看完必懂篇) 具体的原理分析可以参考一下两篇文章,有透彻的分析! 参考资料: 1. https://www.jianshu.com/p/17177c12f84 ...

  7. Java基础知识强化之集合框架笔记79:HashMap的实现原理

    1. HashMap的实现原理之 HashMap数据结构: HashMap是对数据结构中哈希表(Hash Table)的实现, Hash表又叫散列表.Hash表是根据关键码Key来访问其对应的值Val ...

  8. 优秀后端架构师必会知识:史上最全MySQL大表优化方案总结

    本文原作者“ manong”,原创发表于segmentfault,原文链接:segmentfault.com/a/1190000006158186 1.引言   MySQL作为开源技术的代表作之一,是 ...

  9. 牛客网Java刷题知识点之HashMap的实现原理、HashMap的存储结构、HashMap在JDK1.6、JDK1.7、JDK1.8之间的差异以及带来的性能影响

    不多说,直接上干货! 福利 => 每天都推送 欢迎大家,关注微信扫码并加入我的4个微信公众号:   大数据躺过的坑      Java从入门到架构师      人工智能躺过的坑          ...

随机推荐

  1. 泛型约束:接口约束、new()构造函数约束、组合约束(即多种约束合并)

    泛型 接口约束: using System; namespace ConsoleApp1 { /* * * 接口约束:where T:interfaceName * T是类型形参的名称,interfa ...

  2. C# switch语句的使用

    1  今天我们来学习switch 语句的使用,switch 语句和if else 类似 switch 语句主要的作用是用于来判断在规定条件下   根据你的选择来执行switch 语句下面case :的 ...

  3. linux 安装redis 完整步骤

    最近在linux服务器上需要安装redis,来存放数据,增加用户访问数据的速度,由于是第一次安装,于是在百度上搜了一篇文章,按照这篇博客,顺利安装好了,因此将博主的文章拷过来记录一下,方便以后使用,也 ...

  4. NOIP2009-2018简要题解

    口胡警告 NOIP2009 潜伏者 模拟 Hankson 的趣味题 对四个数\(a_0,a_1,b_0,b_1\)分解质因数,结果序列分别记为\(\{p1^{b1}\},\{p2^{b2}\},\{p ...

  5. LeetCode 腾讯精选50题--链表排序

    解题思路:归并 先把链表拆开,分为两部分,一直拆到只剩一个元素后,进行合并,利用一个临时节点记录重排后的链表的起始位置 合并不难,困难点在于如何拆分链表,自己的大体思路是利用两个指针,一个一次移动两位 ...

  6. LeetCode 腾讯精选50题-- 买卖股票的最佳时机 II

    贪心算法: 具体的解题思路如下: II 的解题思路可以分为两部分, 1. 找到数组中差值较大的两个元素,计算差值. 2. 再步骤一最大的元素的之后,继续遍历,寻找差值最大的两个元素 可以得出的是,遍历 ...

  7. 【php设计模式】组合模式

    定义: 是用于把一组相似的对象当作一个单一的对象.组合模式依据树形结构来组合对象,用来表示部分以及整体层次.这种类型的设计模式属于结构型模式,它创建了对象组的树形结构. 应用场景: 部分.整体场景,如 ...

  8. 嵌入式安装telnet

    busybox配置 Defined at networking/Config.in:784 Depends on: TELNET Location: -> Networking Utilitie ...

  9. C# 修改Config文件,增删查改

    版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/BYH371256/article/det ...

  10. mybatis-generator-gui

    mybatis-generator-gui介绍 mybatis-generator-gui是基于mybatis generator开发一款界面工具, 本工具可以使你非常容易及快速生成Mybatis的J ...