Java基础-HashMap源码阅读总结

153 阅读2分钟

文章目录

  • HashMap概述
  • HashMap的数据结构
  • HashMap常用方法的执行流程:get、put、resize

正文

一、HashMap概述

HashMap就是常用的Hash表,用来存储键值对信息,其get、put等方法都达到了常数时间复杂度。除了非同步和禁止null值以外,与HashTable基本完全相同。

二、HashMap的数据结构

常用属性
  • Node[] table , 存储HashMap中的所有节点,节点可能是普通的Node或者是树化后的TreeNode
  • loadFactor: 负载因子,衡量table中的拥塞情况,如果希望获取较高的查询效率,减小负载因子;如果希望节省存储空间,应该调高负载因子
  • threshold:临界点,当表中的元素超过了threshold时,会进行resize操作
常用方法
查询 V get(K key)
1. 计算key的hash值,定位table中桶的位置
2. 如果首节点是空,直接返回;如果首节点的key等于查询的key,直接返回首节点的value值
3. 如果节点为TreeNode, 代表该链表已经treeify了,则调用getTreeNode返回目标节点;如果该节点为Node,则遍历链表,返回目标节点。

新增 V put(K key, V value)
调用putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict)插入节点
hash: key的hash值
key: 插入的键
value: 插入的值
onlyIfAbsent:true代表,如果table中包含该key的节点就不插入
evict: 估计和LinkedHashMap有关,还没搞明白,之后补上

1. 计算key的hash值,定位table中桶的位置
2. 如果首节点为空,直接插入到首节点的位置,返回
3. 如果节点为TreeNode,调用putTreeVal方法定位到红黑树中值为key的节点;如果节点为Node,则遍历链表,定位到链表中值为key的节点
4. 如果定位到的节点不为null,则改变定位到的节点的value值;如果为null说明节点已经插入到红黑树中或是添加到了链表尾部,在插入的
过程中,如果链表的长度大于8会调用treeifyBin将链表转换为红黑树
5. 如果节点中的size大于了threshold,则调用resize方法进行扩容

扩容操作 resize()

  1. HashMap的扩容是将桶扩容的原来的2倍,并且桶的个数必须是2的n次方的形式
  2. 因为HashMap的桶长度的特点,节点经过rehash后要么是在原来的位置,要么是在新增的桶中,根据这个特点resize操作会将链表分为2条链,最后将两条链表挂在不同的桶上。