HashMap简要归纳汇总

130 阅读2分钟

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
  1. 计算key的hash值: 获取key的hashcode值h(key.hashCode()),然后对h做无符号右移16位(h>>>16),最终对两者做异或(^)运算得到key的hash值 hash = (h = key.hashCode()) ^ (h >>> 16)
  2. 计算数组下标: 设定数组容量为n,n-1然后和key的hash值做与(&)运算,数组下标index=(n - 1) & hash
  3. 存入数组: 当数组下标index在数组不存在时,直接生成节点存入数组中
  4. 插入链表或红黑树: 当数组下标index在数组存在时,如果key值相等(node.key == key || node.key.equals(key))则覆盖原节点的值,若不等则插入链表(jdk1.7采用头插法,jdk1.8采用尾插法),链表长度大于8时转为红黑树(jdk1.8时才有此操作),
  5. 扩容: 如果HashMap的大小超过了扩容阈值threshold(capacity * loadFactor)则需要进行扩容
  • get
  1. 和put一样先计算key的hash值hash = (h = key.hashCode()) ^ (h >>> 16)
  2. 和put一样计算得出数组下标值index=(n - 1) & hash
  3. 根据index取出数组中的节点,若key相等则返回该节点的值
  4. 若key不相等则遍历当前链表或红黑树,直到key相等则返回该节点的值