HashMap原理
数据结构
- 数组+链表+红黑树+hash算法
属性
- loadFactor:加载因子。作用:主要参与计算阈值大小的
- table:数组。作用:用来存放数据
- size:HashMap存放元素的数量。作用:记录存放元素的数量,以及参与判断是否需要扩容条件之一
- threshold:阈值。作用:当table数组中存放的数据量达到阈值大小,则进行扩容。计算方式:table.length*loadFactor
- modCount:操作次数。作用:每次对HashMap的操作几次
new
HashMap()
- 设置默认加载因子大小。loadFactor = DEFAULT_LOAD_FACTOR(0.75f)
HashMap(int initialCapacity)
- initialCapacity参数意义:自定义阈值大小
- 默认设置加载因子大小。loadFactor = DEFAULT_LOAD_FACTOR(0.75f)
HashMap(int initialCapacity, float loadFactor)
- initialCapacity:自定义阈值
- loadFactor:自定义加载因子
put原理
- 根据key计算出hash值,计算方式:(h = key.hashCode()) ^ (h >>> 16)
- 判断table是否为空,如果为空,则调用resize函数,进行初始化
- table数组初始化,大小为16
- threshold阈值初始化,大小为12
- 根据hash值计算出当前元素应该存放的位置(即table数组的下标),计算方式:i = (table.length - 1) & hash
- 根据下标i,取出table数组下标i的元素p
- 若p为空,则直接创建对象Node,并放入table数组的i下标内。
- 若p不为空,则判断p的key与当前需要存入数据的key是否一致,如果是,则返回该对象e
- 若不一致,则判断p对象是否为树结构(TreeNode)
- 若p为树结构(红黑树),则调用putTreeVal函数
- putTreeVal:循环遍历该树结构,根据key查找对应的元素e
- 若e不存在,则直接创建对象TreeNode,并放入该树中,然后再调用moveRootToFront函数(重置根根节点),balanceInsertion函数(树化元素)
- 若e存在,则返回该对象e
- 否则(即链表),循环该链表结构,根据key查找对应的元素e
- 若e存在,则返回该对象e
- 若e不存在,则直接创建对象Node,并放入该链表的最后一位。
- 若该链表长度>=8,则调用treeifyBin函数,把链表转换为红黑树(链表长度>=8,且table的长度超过64,否则进行扩容)
- 最终若元素e不为空(key已存在),则把e元素的value替换成新值,并返回原value
- 最终若元素e为空(key不存在),则size+1,若size超过阈值,则调用resize函数,进行扩容
注释
在特殊情况下,HashMap有存放8个元素,就会扩容