如果大家有仔细阅读过 HashMap
的源码就会发现 HashMap
的哈希表初始化并不是在其构造函数中进行的,而是 resize()
方法。
这篇文章不对 HashMap
中的树进行介绍。
一、HashMap 四个构造函数
这里把 HashMap
的四个构造函数全贴出来,主要是给大家一个参照。
PS:并不是所有的构造函数都初始化了 threshold
,但是所有的构造函数都初始化了加载因子,另外初始容量大小也都没有初始化。
// 构造函数 1
public HashMap(int initialCapacity, float loadFactor) {
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal initial capacity: " +
initialCapacity);
if (initialCapacity > MAXIMUM_CAPACITY)
initialCapacity = MAXIMUM_CAPACITY;
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal load factor: " +
loadFactor);
this.loadFactor = loadFactor;
this.threshold = tableSizeFor(initialCapacity);
}
// 构造函数 2
public HashMap(int initialCapacity) {
this(initialCapacity, DEFAULT_LOAD_FACTOR);
}
// 构造函数 3
public HashMap() {
this.loadFactor = DEFAULT_LOAD_FACTOR;
}
// 构造函数 4
public HashMap(Map<? extends K, ? extends V> m) {
this.loadFactor = DEFAULT_LOAD_FACTOR;
putMapEntries(m, false);
}
二、put 方法
我们都知道 HashMap
的底层是一个基于 Node<K,V>[] table
的数组,看完了上面的构造函数,我们发现数组并不是在构造函数中完成的,那是在哪里初始化的呢?带着这个疑问我们来看一下 HashMap
中的 put
方法。
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
/**
* Implements Map.put and related methods
*
* @param hash hash for key
* @param key the key
* @param value the value to put
* @param onlyIfAbsent 为 true 时不改变已经存在的值
* @param 为 false 时表示哈希表正在创建
* @return previous value, or null if none
*/
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
/**
* tab:哈希表数组
* p:桶位置上的头节点
* n:哈希表数组大小
* i:下标(槽位置)
*/
Node<K,V>[] tab; Node<K,V> p; int n, i;
// 当哈希表数组为 null 或者长度为 0 时,初始化哈希表数组
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);
// 哈希碰撞
else