put方法分析
public V put(K key,V value){
return putVal(hash(key),key,value,false,true);
}
hash方法解析
//减少hash冲突
static final int hash(Object key){
int k ;
//将hashcode和高16位做一次异或运算,减少hash冲突
return key==null? 0:(k=key.hashCode())^(k>>>16);
}
putVal方法具体实现(
- 计算散列位置时,hash%2^n = hash&(2^n-1),
- 理论上是将hash值对散列表长度 n(默认长度 16)取模,实际则转换成了与运算。
- 抽象成计算式:X % 2^n = X & (2^n - 1)
)
final V putVal(int hash,K key,V value,boolean onlyIfAbsent,boolean evict){
Node<K,V>[] tab,Node<K,V> p,int n,int i;
if ((tab=tables)==null||(n=tab.length)==0) {
resize();
}
//计算待插入元素的数组下标
if ((p=(tab[i=(n-1)&hash]))==null) {
tab[i] = newNode(hash,key,value,null);
//发生hash冲突
}
else{
K k;Node<K,V> e;
//key和数组首节点元素相同
if (hash==p.hash&&((k=p.key )== key ||k!=null&& k.equals(key))) {
e = p;
//如果hash值不为首节点,判断是否是红黑树的结点,如果是添加到红黑树中,如果key已存在返回
}else if (p instanceof TreeNode) {
e = ((TreeNode<K,V>)p).putTreeNodeval(this,tab,hash,key,value);
//在链表中
}
else{
for (int bitCount =0; ;bitCount++ ) {
//遍历找到链表的尾结点
if ((e=p.next())==null) {
p.next = newNode(hash,key,value,null);
//判断链表上结点个数是否为8,如果大于等于8将结点转为红黑树
if (bitCount>=TRFFIFY_THRESHOLD-1) {
treeifyBin(tab,hash);
}
break;
}
//和链表上结点的key相同
if (e.hash==hash&& ((k=e.key)==key || (k!=null && k.equals(e.key)))) {
break;
}
p = e;
}
}
//key相同,待插入的key有重复
if (e!=null) {
V oldValue = e.value;
if (!onlyIfAbsent||oldValue==null) {
e.value = value;
}
afterNodeAccess(e);
return oldValue;
}
}
//待插入的key没有重复,插入成功e结点的值为null
modCount++;
//如果元素个数>临界值(数组长度*加载因子),则扩容
if (++size>threshold) {
resize();
}
afterNodeInsertion(evict);
return null;
}