HashMap深入解析

兄弟姐妹

HashMap:快,遍历顺序不确定,非线程安全
Hashtable:遗留类,线程安全,只有一个线程能写,并发性能较差
LinkedHashMap:记录插入顺序
ConcurrentHashMap:线程安全,分段锁

HashMap是什么

从结构实现来讲,HashMap是数组+链表+红黑树(JDK1.8增加了红黑树部分)实现的,如下如所示。


HashMap结构

重要组成:
Node:实现了Map.Entry接口,本质是就是一个映射(键值对)。
Node[] table:哈希桶数组
int threshold:所能容纳的k-v对极限(table.length * load factor)
final float loadFactor:负载因子
int modCount:结构变化次数(put新的算,但是覆盖value不算)
int size:当前map中的k-v数量

设计思路

本质:空间成本和时间成本之间权衡

其实就是在根据实际情况确定哈希桶数组的大小,并在此基础上设计好的hash算法减少Hash碰撞。
那么通过什么方式来控制map使得Hash碰撞的概率又小,哈希桶数组(Node[] table)占用空间又少呢?答案就是好的Hash算法和扩容机制。

在HashMap中,哈希桶数组table的长度length大小必须为2的n次方(一定是合数),这是一种非常规的设计,常规的设计是把桶的大小设计为素数。相对来说素数导致冲突的概率要小于合数。主要是为了在取模和扩容时做优化,同时为了减少冲突,HashMap定位哈希桶索引位置时,也加入了高位参与运算的过程。

原理实现

1.确定哈希桶数组索引位置
hash()、取模运算的巧妙(来计算该对象应该保存在table数组的哪个索引处,当length = 2^n时,h&(length-1) = h%length,&比%更高效)


取模运算

2.分析HashMap的put方法
putVal()


put()

3.扩容机制
遍历旧的数组和所有node,重新计算hash,再refresh。
区别1.7和1.8(引入红黑树)


分布散列的时候

很极端

小结

1.扩容是特别消耗性能的,在能估算map大小的时候,可以初始化一个数值。
2.HashMap是线程不安全的,会造成死循环
3.jdk1.8中的红黑树对HashMap的性能优化

拓展

Hash哈希

  • 可变数据类型的操作改变,导致哈希值的改变

ConcurrentHashMap

  • 分段锁
  • 对于size()的统计

参考

Java8系列之重新认识HashMap
漫画:什么是ConcurrentHashMap?

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 简介 Java为数据结构中的映射定义了一个接口java.util.Map,此接口主要有四个常用的实现类,分别是Ha...
    bbe9e62bc5ba阅读 422评论 0 4
  • 一、简介 哈希表也叫散列表,是一种非常重要的数据结构,底层实现是一个 key - value 键值对。应用场景及其...
    进击的程序猿呀阅读 134评论 0 0
  • 1.概述 HashMap是日常java开发中常用的类之一,是java设计中非常经典的一个类,它巧妙的设计思想与实现...
    Garwer阅读 2,256评论 1 28
  • 摘要 HashMap是程序猿使用频率最高的用于映射(键值对)的数据类型。JDK1.8对HashMap进行了优化,例...
    一凡呀阅读 740评论 0 2
  • HashMap底层原理解析 1.基本、常用性质HashMap储存的是键值对HashMap 允许 null 键和 n...
    潇萧之炎阅读 648评论 0 1