HashMap底层源码分析
HashMap主要是用来存放键值对的,它基于哈希表的Map接口实现,是常用的Java集合之一,是非线程安全的。
HashMap可以存放null的Key和value,但是null作为键只能有一个,作为value可以有多个
方法名称 | 说明 |
---|---|
V put(K key, V value) | 添加元素 |
V remove(Object key) | 根据键删除键值对元素 |
void clear() | 移除所有的键值对元素 |
boolean containsKey(Object key) | 判断集合是否包含指定的键 |
boolean containsValue(Object value) | 判断集合是否包含指定的值 |
boolean isEmpty() | 判断集合是否为空 |
int size() | 集合的长度,也就是集合中键值对的个数 |
HashMap结构
HashMap内部方法
图标为m
表示method
HashMap内部类
图标为c
表示class
HashMap内部属性
图标为f
表示field
1 | static class Node<K,V> implements Map.Entry<K,V> {} |
HashMap中每个元素都是一个Entry对象
jdk1.7及之前的底层实现为:数组+链表
jdk1.8之后的底层实现为:数组+链表+红黑树
1 | // 表示数组默认的大小 为16 |
构造方法
空参构造方法只是进行loadFactor
进行了初始化
1 | public HashMap() { |
HashMap中的Hash值只与键有关系与值无关
1 | public V put(K key, V value) { |
>>>
表示无符号右移
扩容机制
调用空参构造的时候,只把属性loadFactor
初始化为0.75
剩余的核心源码主要涉及到PUT操作:【put操作首先通过hash值定位到数组下标】
- 如果当前位置没有值,则直接在数组中添加该键值对,即Node对象
- 如果数组长度超过其初始长度16*0.75=12的时候,则会进行扩容,扩容成原来的2倍
- 如果当前位置有值,在判断两者的key是否相等:
- key一样:
- 则进行覆盖更新
- key不一样:
- 则在其后以链表的形式进行追加。
- 当链表的长度达到8【
TREEIFY_THRESHOLD
】的时候,则会调用treeifyBin()
方法,此方法会根据HashMap数组长度来判断是否需要转成红黑树。只有当数组长度大于或者等于64【MIN_TREEIFY_CAPACITY
】的情况下,才会执行转换红黑树的操作,以减少搜索时间。否则就只执行resize()
方法对数组进行扩容。
- key一样:
get操作:
判断是否存在以key为key的键值对映射,如果不存在返回null;如果存在则返回e.value