开始之前先说一下HashMap的基本参数
- 默认长度 16
- 数组最大长度 30
- 负载因子 0.75f
- 链表转红黑树条件I 链表长度>8
- 红黑树转链表条件 红黑树长度<6
- 链表转红黑树条件II 数组容量>64
put方法源码:
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
/**
*
* @param hash hash方法计算hash值 详情见本方法下
* @param key 传入key
* @param value 传入value
* @param onlyIfAbsent
* @param evict
* @return
*/
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V>[] tab; //定义哈希表(数组)
Node<K,V> p; //当前位置的数据
int n, i;//n是hash数组长度
if ((tab = table) == null || (n = tab.length) == 0)//if(没有hash数组)or(hash数组.length为0)
n = (tab = resize()).length;//初始化/扩容数组
if ((p = tab[i = (n - 1) & hash]) == null)//hash值%数组长度||hash值&(数组长度-1)[两个效果是一样的]
//(n - 1) & hash确定该元素在hash数组内的位置
//if这个位置的元素为null,创建一个Node,将数据存进去
tab[i] = newNode(hash, key, value, null);
else {//if这个位置已有元素(即不为null)
Node<K,V> e; K k;
//(key的hash值相同)&(该位置的key==当前传入的key)||(当前传入的key.equals(该位置key))
//意思就是出现相同key的情况下
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;//记录一下,下面会将value进行覆盖
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) {
//new一个新Node挂载到p.next上
p.next = newNode(hash, key, value, null);
//binCount 链表的长度,if(binCount>=8)触发链表转红黑树的机制
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
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
//与上面相呼应,用当前key的值覆盖掉之前的值
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;//覆盖value
afterNodeAccess(e);
return oldValue;
}
}
++modCount;
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}
put中用到的其他方法:
hash方法:计算hash值
/*
根据传入key的hashcode获得hash值
为什么HashMap可以存储key为null的数据??
如果key为null,它会将null隐式转换为0进行存储!!
(h = key.hashCode()) ^ (h >>> 16)
经过处理后使得hash值的重复率降低
key的hashcode^无符号右移16位,
*/
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
treeifyBin方法: 链表转红黑树机制
final void treeifyBin(Node<K,V>[] tab, int hash) {//(链表长度>8)[先天条件]
int n, index; Node<K,V> e;
//if(数组为空||数组的长度<64)
if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
resize();//数组扩容==>2倍
else if ((e = tab[index = (n - 1) & hash]) != null) {
TreeNode<K,V> hd = null, tl = null;
do {//将链表转为红黑树的具体实现
TreeNode<K,V> p = replacementTreeNode(e, null);
if (tl == null)
hd = p;
else {
p.prev = tl;
tl.next = p;
}
tl = p;
} while ((e = e.next) != null);
if ((tab[index] = hd) != null)
hd.treeify(tab);
}
}