HashMap源码解析
简介
HashMap是一个根据键值(Key)而直接访问在内存存储位置的数据结构。也就是说,它通过计算一个关于键值的函数,将所需查询的数据映射到表中的一个位置来访问记录,这加快了查找速度。这个映射函数称作散列函数,存放记录的数组称作散列表。
HashMap继承了AbstractMap,实现了Map、Cloneable、Serializable接口。
1 | public class HashMap<K,V> extends AbstractMap<K,V> |
HashMap很奇怪,明明继承了AbstractMap(AbstractMap实现了Map接口),却又自己实现了Map接口。这个原因可以参考StackOverflow上的这个回答。
实现了Cloneable接口,重写了clone方法
实现Serializable接口,支持序列化和反序列化
实现逻辑
HashMap使用Node节点和Node数组来实现逻辑的。
主要属性
- DEFAULT_INITIAL_CAPACITY:HashMap初始化大小,默认为16
- DEFAULT_LOAD_FACTOR:HashMap初始化负载因子,默认0.75
- TREEIFY_THRESHOLD:HashMap冲突链表转为红黑树的阈值,默认是8
- UNTREEIFY_THRESHOLD:HashMap冲突红黑树转为链表的阈值,默认是6
- MIN_TREEIFY_CAPACITY:HashMap的数量阈值,到达64之后才允许将冲突链表转为红黑树
- table:存放数据的Node数组
- size:HashMap的大小
- modCount:用于快速失败的计数
主要函数
构造函数
无参构造函数
使用默认参数,创建HashMap
1 | public HashMap() { |
有参构造函数(指定大小)
1 | public HashMap(int initialCapacity) { |
HashMap会生成一个最接近于指定大小的2的N次幂大小的HashMap.比如,指定大小为11,那么HashMap会生成一个大小为16的HashMap。
有参构造函数(指定大小和负载因子)
同上,支持指定负载因子。大小也会被扩大为最接近它的2的N次幂大小。
1 | public HashMap(int initialCapacity, float loadFactor) { |
有参构造函数(指定容器)
1 | public HashMap(Map<? extends K, ? extends V> m) { |
size()
1 | public boolean isEmpty() { |
isEmpty()
1 | public boolean isEmpty() { |
get(Object)
1 | public V get(Object key) { |
get方法调用了getNode方法
getNode()
1 | final Node<K,V> getNode(int hash, Object key) { |
- 首先判断Node数组是不是空的
- 再判断头结点的Hash值和key是否相等,相等的话直接返回头结点
- 如果当前节点是树节点,在红黑树中找
- 如果不是树节点,则在链表中找
- 如果都找不到,返回null
containsKey(Object)
1 | public boolean containsKey(Object key) { |
判断getNode方法返回的对应值是否为null
put(Object, Object)
1 | public V put(K key, V value) { |
put方法调用了内部方法oytVal来插入数据
putVal方法
1 | final V putVal(int hash, K key, V value, boolean onlyIfAbsent, |
- 首先判断当前Node数组是否为空,是的话,调用resize方法初始化数组
- 通过Hash值,找到数据在数组中对应的索引值,如果当前索引值处数据位null,就新生成一个节点插入
- 定位到Hash冲突的节点
- 如果当前节点是树节点,加入到树中
- 如果当前节点是链表节点,在链表尾新增一个节点
- 如果新增节点之后,链表长度超过阈值,则转为红黑树
- 如果当前key已经在Map中了,那么就在29行开始处,更新已有的值
- 接着判断当前大小是否超过阈值,是的话,哈希表扩容
resize方法
1 | final Node<K,V>[] resize() { |
remove(Object)
1 | public V remove(Object key) { |
调用方法removeNode实现移除逻辑
removeNode()
1 | final Node<K,V> removeNode(int hash, Object key, Object value, |
- 首先,找到对应符合条件的Node
- 移除
clear()
1 | public void clear() { |
- 将size置为0
- 遍历node数组,每个值都置为null