HashMap底层原理
一、存储结构
HashMap是数据结构散列表在Java中的实现版本,通过对键值进行哈希函数计算出键值对在散列表中的下标位置,可以快速访问到相应数据,时间复杂度为O(1)。
但因散列表数组长度有限,不同键值经过哈希函数计算出的下标位置可能一致,引发哈希冲突,为了解决这个问题,通常将哈希冲突的数据组成一个链表挂到散列表桶节点上,jdk7及以前版本都是如此处理,时间复杂度为O(n),结构如下图:
文章图片
jdk8中对链表结构做了优化,在一定条件下将链表转为红黑树,提升查询效率。红黑树是一种二叉平衡树,时间复杂度为O(logn),结构如下图:
文章图片
二、存取原理
put()方法
- 调用哈希函数hash(key)计算出键值key的哈希值hash,再用此哈希值hash和散列表长度-1 做与运算得到数组下标;
- 根据数组下标找到目标bucket,如果bucket上没有任何元素,就根据键值对创建一个新节点Node,赋值给该bucket上;
- 如果当前bucket上有链表,且头结点就匹配(哈希值hash相等,key值相同或equals相等),那么就将头结点上的值value替换;
- 若第2、3步不满足,当前bucket上的头结点是树结构结点类型TreeNode,则转为红黑树的插入操作;
- 若第2、3、4步都不满足,则对链表做遍历操作;
? 1)若链表中有节点匹配,则做value替换;
? 2)若没有结点匹配,则在链表末尾追加;(jdk7使用头插法,jdk8使用尾插法)
? 3)检查链表长度是否超过TREEIFY_THRESHOLD
(默认大小为8),若超过则执行红黑树转换操作;
- 以上操作执行完之后,再检查当前键值对的数量比例是否超过了负载因子,若超出,则进行扩容。
- 根据key计算出hash值,进一步计算得到哈希表的目标下标index;
- 若目标bucket头结点匹配,就返回头结点的value;
- 若目标bucket上为红黑树,则在红黑树上查找;若不是红黑树,遍历链表;
- 若都没匹配到,返回null;
【HashMap底层原理】一般情况下,当键值对数量比例超过负载因子便会触发扩容。每次扩容后的容量都是之前容量的2倍。
四、线程不安全
推荐阅读
- 做一件事情的基本原理是什么()
- 【读书笔记】贝叶斯原理
- SG平滑轨迹算法的原理和实现
- “写作宝典”《金字塔原理》之读书笔记
- 医生随笔(232)不要轻易得罪底层人
- Spring|Spring 框架之 AOP 原理剖析已经出炉!!!预定的童鞋可以识别下发二维码去看了
- Spring|Spring Boot 自动配置的原理、核心注解以及利用自动配置实现了自定义 Starter 组件
- Vue源码分析—响应式原理(二)
- MYSQL主从同步的实现
- (1)redis集群原理及搭建与使用(1)