您的位置:首页 > 其它

HashMap源码阅读(2)-put操作

2016-04-12 00:00 197 查看
1

public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}

static final int hash(Object key) {
int h;
//k求的hashCode后, 高16位和低16位做异或运算(同则0,异则1,11->0,00->0, 10->1)
//为什么呢?减少碰撞.
//为什么能减少碰撞?
/*
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null)
*/
// n 是2的幂次方, 因此n-1的二进制,除了符号位是0,其他都是1; 因为做&运算后结果的离散性,取决于hash值的离散性
// 生活中都有规律,使用的key要么一般偏小(整型,多是short),要么偏大(长字符串的hash). 高低8位做异或,打破规律.(自己胡诌的.......)
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); //无符号右移16位,高位补0
//  111111111 11111111 11111111 11111111 ^ 00000000 00000000 00000000 01111001
//
}

/*
1 首次插入,要初始化table,分配空间
2 是否有碰撞:
a 无,则插入
b 有,则需要遍历链表(或红黑树)查找是否存在相同的key [ 碰撞耗费性能 ]
ba: 存在相同的key-> 替换
bb: 不存在相同的key,插入尾部
*/
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;

if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;// 1 HashMap是lazy的.第一次put时,才调用resize,初始化table,分配空间
// 如果未发生碰撞
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 && // 如果key的hash值相同,且equals(或同一内存地址->同一对象)
((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) {//到了链表末尾
p.next = newNode(hash, key, value, null);//链表末尾新增一个节点
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash);// 链表节点数超过阈值,将其转换成为红黑树
break;
}

// 遍历链表,查找是否有key相同的元素
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break; //如果有,则break, 此时e为key相同的节点
p = e;
}
}
if (e != null) { // existing mapping for key
V oldValue = e.value; // 对value做替换
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue; //返回旧的value
}
}
++modCount;//对修改次数加1
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: