put添加相关方法和属性
[code] /** * Associates the specified value with the specified key in this map. * If the map previously contained a mapping for the key, the old * value is replaced. * * @param key key with which the specified value is to be associated * @param value value to be associated with the specified key * @return the previous value associated with key, or * null if there was no mapping for key. * (A null return can also indicate that the map * previously associated null with key.) */ //将指定值与此映射中的指定键相关联。如果映射之前包含键的映射,则替换旧值。 //参数: key–与指定值关联的键 value–与指定键关联的值 //返回值: 与键关联的前一个值,如果没有键的映射,则为null。(null返回还可以指示映射先前将null与键关联。) public V put(K key, V value) { return putVal(hash(key), key, value, false, true); } /** * Implements Map.put and related methods. * * @param hash hash for key * @param key the key * @param value the value to put * @param onlyIfAbsent if true, don't change existing value * @param evict if false, the table is in creation mode. * @return previous value, or null if none */ //实施映射。put和相关方法。 //参数: hash–密钥的哈希 key–钥匙 value–要放置的值 onlyIfAbsent–如果为true,则不更改现有值 evict-如果为false,则表处于创建模式。 //返回值: 上一个值,如果没有则为null final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) { Node[] tab; Node p; int n, i; //检查HashMap中是否为空,为空则使用resize初始化,并给n赋值 if ((tab = table) == null || (n = tab.length) == 0) n = (tab = resize()).length; //检查数组下标处是否为空,是则直接赋值((n - 1) & hash 为下标) if ((p = tab[i = (n - 1) & hash]) == null) tab = newNode(hash, key, value, null); else { Node e; K k; //检查数组下标处key是否与新值重复,是则e的值为 key if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))) e = p; //检查是否是红黑树,是则使用红黑树插入,否则链表插入 else if (p instanceof TreeNode) //红黑树不了解 e = ((TreeNode)p).putTreeVal(this, tab, hash, key, value); else { // 循环遍历链表,如果找到相同key则替换,没有找到则插入到链表最后并检查是否超过8,是则将链表转化为红黑树 for (int binCount = 0; ; ++binCount) { // 检查p是否为最后一个元素,此时结束循环e为 null if ((e = p.next) == null) { //新元素尾插到末尾 p.next = newNode(hash, key, value, null); //检查链表长度是否超过八,是则转化为红黑树, if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st //构造树的具体方法 treeifyBin(tab, hash); break; } // 检查元素是否与新元素相同,是则退出循环,此时结束循环e值为 key if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) break; p = e; } } // 这句话的意思其实是判断上面的循环走完了吗?如果走完链表则e应该是null,如果e不为空则表示新值还没有被替换,再这里替换 if (e != null) { // existing mapping for key // 将e的值赋给oldValue做中转 V oldValue = e.value; // 判断条件是 是否改变现有值 新值是否为null if (!onlyIfAbsent || oldValue == null) e.value = value; afterNodeAccess(e); // 返回替换前的值 return oldValue; } } ++modCount; // 判断是否到达扩容界限 threshold = 容量 * 负载因子(默认0.75) if (++size > threshold) // 扩容 resize(); afterNodeInsertion(evict); return null; } /** * Initializes or doubles table size. If null, allocates in * accord with initial capacity target held in field threshold. * Otherwise, because we are using power-of-two expansion, the * elements from each bin must either stay at same index, or move * with a power of two offset in the new table. * * @return the table */ //初始化或加倍表大小。如果为空,则根据字段阈值中保持的初始容量目标进行分配。 //因为我们使用的是二次幂展开,所以每个bin中的元素必须保持在同一索引中,或者在新表中以二次幂偏移量移动。 //返回值: table //HashMpa的扩容方法 final Node[] resize() { Node[] oldTab = table; // 判断HahsMap是否为空给oldCap(旧容量)赋值 int oldCap = (oldTab == null) ? 0 : oldTab.length; // 旧的容量界限 int oldThr = threshold; // 新的容量和新的容量界限 int newCap, newThr = 0; // 判断是否HashMap第一次初始化 if (oldCap > 0) { // 判断旧容量是否大于等于最大,是则提升界限,并将容器直接返回 if (oldCap >= MAXIMUM_CAPACITY) { // 将界限提升到2的31次方 - 1 threshold = Integer.MAX_VALUE; // 返回原容器 return oldTab; } //判断旧容量扩大2倍后是否超过最大容量,判断旧容量界限是否大于等于初始容量(保证不是第一次初始化容器) //