HashMap涉及的技术点非常多,典型的数据结构和算法有机结合,JDK对HashMap优化变化中不断权衡时间复杂和空间复杂度。
一. 存储结构
1.JDK1.8之前 HashMap = 数组(O(1))+ 单向链表(O(n))
2.JDK1.8之后 HashMap = 数组(O(1))+ 单向链表(O(n))+ 红黑树(O(log n)
![89f322caa25bfd9f13838ec20cfe25ed.png](https://i-blog.csdnimg.cn/blog_migrate/55b29c9d865fc2d659f83748af38b183.jpeg)
关于结构的几个关键数字: 1.默认初始化数组容量大小是16。 2.数组扩容刚好是2的次幂。 3.默认的加载因子是0.75。 4.链表长度超过8时将链表转化成红黑树结构。 5.红黑树节点数减少到6的时候退化成链表。 以上几个数字关系,又为什么是上边的几个数字接下来一个个分析。
二. 操作原理
1. put储存流程
①计算桶的位置,根据key的hashcode求出hash值,位置index = hash%length。
②判断是否达到扩容条件,threshold=DEFAULT_INITIAL_CAPACITY * loadFactor(16*0.75=12)大于这个阀门值就需要扩容,否则下一步。
③判断桶位置是否为空,如果为空直接在数据插入数据。如果不为空,下一步。
④判断是链表还是红黑树,链表是否到达转化红黑树,当前链表节点数<=8,插入节点;如果是红黑树插入节点,否则下一步。
⑤链表转化成红黑树,插入节点。
⑥插入节点后计算当前size是否需要扩容,如果大于阀门值需要扩容resize。
/** * Implements Map.put and related methods * * @param hash hash for key * @param key the key * @param value the value to put * @param onlyIfAbsent if true, don't change existing value * @param evict if false, the table is in creation mode. * @return previous value, or null if none */final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) { Node[] tab; Node p; int n, i; if ((tab = table) == null || (n = tab.length) == 0) n = (tab = resize()).length; if ((p = tab[i = (n - 1) & hash]) == null) tab[i] = newNode(hash, key, value, null);