这里主要讲源码流程,原理只做简单介绍
- hashMap原理浅析
hashMap 的结构是由数组+链表构成,数组为Node[] table,链表节点为Node。
-
map.put(key,value),根据(table.length - 1) & hash(key)进行散列到table的某一个位置。当key值相同时(hash碰撞),则遍历链表(即Node的每一个next),如果有相同key的则覆盖,否则将添加进链表
-
当size > threshold(元素数量大于容纳数量)时进行resize()扩容操作,以原有table*2进行扩容。1.7实现将现有数据进行重新散列;1.8判断e.hash & oldCap == 0(即数组第一位)时在原区间,否则在新增区间同一位置。
-
hashMap基本属性
//默认初始容量-必须是2的幂
DEFAULT_INITIAL_CAPACITY = 1 << 4;
//最大容量
MAXIMUM_CAPACITY = 1 << 30;
//默认负载因子
DEFAULT_LOAD_FACTOR = 0.75f;
//一个桶的树化阈值,当桶中元素个数超过这个值时,使用红黑树替换现有节点
TREEIFY_THRESHOLD = 8
//一个树的链表还原阈值,当扩容时,桶中元素个数小于这个值,就会把红黑树还原成链表
UNTREEIFY_THRESHOLD = 6
/**哈希表的最小树形化容量,
当哈希表中的容量大于这个值时,表中的桶才能进行树形化。
否则桶内元素太多时会扩容,而不是树形化。
为了避免进行扩容、树形化选择的冲突,这个值不能小于 4*TREEIFY_THRESHOLD
*/
MIN_TREEIFY_CAPACITY = 64
//具体的元素存储
Node[] table
//元素的数量
int size
//修改次数
int modCount
//在下一次resize ()调用之前的容量大小,也就是capacity ,默认为capacity*loadFactor
int threshold
//加载因子
float loadFactor
- 源码
hashMap核心Node节点
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
V value;
Node<K,V> next;
插入一个元素
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
1 判断table是否为空,为空新建一个
2 判断key的hash散列是否存在,不存在直接新建一个链表节点
3 判断元素是否和链表第一个元素相同,相同则覆盖
4 循环链表节点
5 判断是不是尾节点,是增新增节点
6 判断是否超过阀值,超过则用红黑树替换链表
7 判断元素是否和链表元素相同,相同则覆盖。循环节点结束
8 对新增或覆盖元素进行value赋值
9 判断是否超过容量,超过则进行扩容
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;
//判断table是否为空
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
//判断key的hash散列是否存在
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
else {
Node<K,V> e; K k;
//判断元素是否和链表第一个元素相同,相同则覆盖
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
else {
for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
if (binCount >= TREEIFY_THRESHOLD - 1)
//**超过阀值,用红黑树替换链表。红黑树代码此处不讨论**
treeifyBin(tab, hash);
break;
}
//判断元素是否和链表元素相同,相同则覆盖
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
//赋值操作
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
++modCount;
//超过容量,进行扩容
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}