The bin count threshold for using a tree rather than list for a bin.
Bins are converted to trees when adding an element to a bin with at
least this many nodes. The value must be greater than 2 and should be at
least 8 to mesh with assumptions in tree removal about conversion back
to plain bins upon shrinkage.
The bin count threshold for untreeifying a (split) bin during a
resize operation. Should be less than TREEIFY_THRESHOLD, and at most 6
to mesh with shrinkage detection under removal.
1
staticfinalintUNTREEIFY_THRESHOLD=6;
The smallest table capacity for which bins may be treeified.
(Otherwise the table is resized if too many nodes in a bin.) Should be
at least 4 * TREEIFY_THRESHOLD to avoid conflicts between resizing and
treeification thresholds.
Computes key.hashCode() and spreads (XORs) higher bits of hash to
lower. Because the table uses power-of-two masking, sets of hashes that
vary only in bits above the current mask will always collide. (Among
known examples are sets of Float keys holding consecutive whole numbers
in small tables.) So we apply a transform that spreads the impact of
higher bits downward. There is a tradeoff between speed, utility, and
quality of bit-spreading. Because many common sets of hashes are already
reasonably distributed (so don't benefit from spreading), and because we
use trees to handle large sets of collisions in bins, we just XOR some
shifted bits in the cheapest possible way to reduce systematic lossage,
as well as to incorporate impact of the highest bits that would
otherwise never be used in index calculations because of table
bounds.
/** * Basic hash bin node, used for most entries. (See below for * TreeNode subclass, and in LinkedHashMap for its Entry subclass.) */ staticclassNode<K,V> implementsMap.Entry<K,V> { finalint hash; final K key; V value; Node<K,V> next;
publicfinal V setValue(V newValue) { VoldValue= value; value = newValue; return oldValue; }
publicfinalbooleanequals(Object o) { if (o == this) returntrue; if (o instanceof Map.Entry) { Map.Entry<?,?> e = (Map.Entry<?,?>)o; if (Objects.equals(key, e.getKey()) && Objects.equals(value, e.getValue())) returntrue; } returnfalse; } }
/** * Returns the value to which the specified key is mapped, * or {@code null} if this map contains no mapping for the key. * * <p>More formally, if this map contains a mapping from a key * k to a value v such that (key==null ? k==null : * key.equals(k)), then this method returns v; otherwise * it returns null. (There can be at most one such mapping.) * * <p>A return value of null does not <i>necessarily</i> * indicate that the map contains no mapping for the key; it's also * possible that the map explicitly maps the key to null. * The {@link #containsKey containsKey} operation may be used to * distinguish these two cases. * 这段话意思就是说有的key是空的,但是不代表这个map没有建立关联的关系 * @see #put(Object, Object) */ public V get(Object key) { Node<K,V> e; return (e = getNode(hash(key), key)) == null ? null : e.value; }
/** * The table, initialized on first use, and resized as necessary. When allocated, length is always a power of two. (We also tolerate length zero in some operations to allow bootstrapping mechanics that are currently not needed.) */ transient Node<K,V>[] table;
/** * Implements Map.get and related methods * * @param hash hash for key 哈希值 * @param key the key 原值 * @return the node, or null if none */ final Node<K,V> getNode(int hash, Object key) { Node<K,V>[] tab; Node<K,V> first, e; int n; K k; if ((tab = table) != null && (n = tab.length) > 0 && (first = tab[(n - 1) & hash]) != null) { //数组非空,把数组赋给tab,长度大于0,而且头结点(用哈希值和数组长度异或)非空 if (first.hash == hash && // always check first node ((k = first.key) == key || (key != null && key.equals(k)))) return first; //看first的key是否等于传入的key if ((e = first.next) != null) { if (first instanceof TreeNode) //如果是红黑树方式存储的 return ((TreeNode<K,V>)first).getTreeNode(hash, key); //调用红黑树寻找treenode do { //链式存储的话链式寻找 if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) return e; } while ((e = e.next) != null); } } //找不到或者长度为空什么的返回空 returnnull; }
/** * 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 <tt>key</tt>, or * <tt>null</tt> if there was no mapping for <tt>key</tt>. * (A <tt>null</tt> return can also indicate that the map * previously associated <tt>null</tt> with <tt>key</tt>.) */ 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 */ 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; //如果tab为空,先创建tab if ((p = tab[i = (n - 1) & hash]) == null) //如果tab中当前hash值不存在先创建该节点 tab[i] = newNode(hash, key, value, null); else { Node<K,V> e; K k; if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))) //对于链表的头节点或者树根,如果该key存在,直接覆盖value e = p; elseif (p instanceof TreeNode) //如果p是红黑树节点,用红黑树的添加方式添加 e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value); else { //链表,顺序添加 for (intbinCount=0; ; ++binCount) { if ((e = p.next) == null) { p.next = newNode(hash, key, value, null); if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st //链表长度大于8转换为红黑树进行处理 treeifyBin(tab, hash); break; } if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) //链表中存在该key break; p = e; } } if (e != null) { // existing mapping for key VoldValue= e.value; if (!onlyIfAbsent || oldValue == null) e.value = value; afterNodeAccess(e); return oldValue; } } ++modCount; if (++size > threshold) //超过最大容量,扩容 resize(); afterNodeInsertion(evict); returnnull; }
/** * Removes the mapping for the specified key from this map if present. * * @param key key whose mapping is to be removed from the map * @return the previous value associated with <tt>key</tt>, or * <tt>null</tt> if there was no mapping for <tt>key</tt>. * (A <tt>null</tt> return can also indicate that the map * previously associated <tt>null</tt> with <tt>key</tt>.) */ public V remove(Object key) { Node<K,V> e; return (e = removeNode(hash(key), key, null, false, true)) == null ? null : e.value; }
/** * Implements Map.remove and related methods * * @param hash hash for key * @param key the key * @param value the value to match if matchValue, else ignored * @param matchValue if true only remove if value is equal * @param movable if false do not move other nodes while removing * @return the node, or null if none */ final Node<K,V> removeNode(int hash, Object key, Object value, boolean matchValue, boolean movable) { Node<K,V>[] tab; Node<K,V> p; int n, index; if ((tab = table) != null && (n = tab.length) > 0 && (p = tab[index = (n - 1) & hash]) != null) { Node<K,V> node = null, e; K k; V v; if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))) node = p; elseif ((e = p.next) != null) { if (p instanceof TreeNode) node = ((TreeNode<K,V>)p).getTreeNode(hash, key); else { do { if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) { node = e; break; } p = e; } while ((e = e.next) != null); } } if (node != null && (!matchValue || (v = node.value) == value || (value != null && value.equals(v)))) { if (node instanceof TreeNode) ((TreeNode<K,V>)node).removeTreeNode(this, tab, movable); elseif (node == p) tab[index] = node.next; else p.next = node.next; ++modCount; --size; afterNodeRemoval(node); return node; } } returnnull; }