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
static class Node<K,V> implements Map.Entry<K,V> {}
HashMap中每个元素都是一个Entry对象,
数组+链表+红黑树
// 表示数组默认的大小 为16
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16// 表示默认的负载因子(加载因子)为0.75
// 当数组元素个数超过0.75*16=12的时候就进行扩容,扩容为原来的2倍空间大小
static final float DEFAULT_LOAD_FACTOR = 0.75f;// 表示HashMap最大的空间为 1073741824
static final int MAXIMUM_CAPACITY = 1 << 30;
构造方法
public HashMap() {this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}
HashMap中的Hash值只与键有关系与值无关
public V put(K key, V value) {return putVal(hash(key), key, value, false, true);
}// 返回键所对应的哈希值
static final int hash(Object key) {int h;return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
>>>
表示无符号右移
扩容机制
调用空参构造的时候,只把属性loadFactor
初始化为0.75
剩余的核心源码主要涉及到put操作:
- 如果当前位置没有值,则直接在数组中添加该键值对,即Node对象
- 如果数组长度超过其初始长度16*0.75=12的时候,则会进行扩容,扩容成原来的2倍
- 如果当前位置有值,需要判断和当前新添加的键是否一致: PUT操作
- 一致:
- 则进行覆盖更新
- 不一致:
- 则在其后以链表的形式进行追加。
- 当链表的长度达到8【
TREEIFY_THRESHOLD
】的时候,则会调用treeifyBin()
方法,此方法会根据HashMap数组长度来判断是否需要转成红黑树。只有当数组长度大于或者等于64【MIN_TREEIFY_CAPACITY
】的情况下,才会执行转换红黑树的操作,以减少搜索时间。否则就只执行resize()
方法对数组进行扩容。
- 一致:
get操作:
判断hash和key是否相等,如果是就直接返回,如果不是,需要判断是否是红黑树,是的话按照红黑树的方式进行搜索;如果也不是红黑树就按照链表的顺序从前往后进行遍历查找。