1java
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; }