HashMap
jdk1.7和jdk1.8之间区别
- jdk1.7
数据结构: 数组+链表 链表是头插法(
并发下可能会造成环形链表,陷入死循环)
- jdk1.8
数据结构: 数组+链表+红黑树(
链表超过8个后转为红黑树,低于6个转为链表) 链表是尾插法
关键参数
- capacity: 数组容量,默认16,后续扩容后的数组为当前容量的2倍
- loadFactor: 负载因子0.75
- threshold: 扩容的阈值,等于
capacity * loadFactor
假设当前数组容量为32,则当
HashMap.size>=(32*0.75=24)时则开始扩容,扩容后数组容量为64
注意HashMap的实际大小不等同于本文中所说的数组容量
执行流程
- put
- 计算key的hash值: 获取key的hashcode值h(key.hashCode()),然后对h做无符号右移16位(h>>>16),最终对两者做异或(^)运算得到key的hash值
hash = (h = key.hashCode()) ^ (h >>> 16)- 计算数组下标: 设定数组容量为n,n-1然后和key的hash值做与(&)运算,数组下标
index=(n - 1) & hash- 存入数组: 当数组下标index在数组不存在时,直接生成节点存入数组中
- 插入链表或红黑树: 当数组下标index在数组存在时,如果key值相等(
node.key == key || node.key.equals(key))则覆盖原节点的值,若不等则插入链表(jdk1.7采用头插法,jdk1.8采用尾插法),链表长度大于8时转为红黑树(jdk1.8时才有此操作),- 扩容: 如果HashMap的大小超过了扩容阈值
threshold(capacity * loadFactor)则需要进行扩容
- get
- 和put一样先计算key的hash值
hash = (h = key.hashCode()) ^ (h >>> 16)- 和put一样计算得出数组下标值
index=(n - 1) & hash- 根据index取出数组中的节点,若key相等则返回该节点的值
- 若key不相等则遍历当前链表或红黑树,直到key相等则返回该节点的值