//Hash table based implementation of the {@code Map} interface. This //implementation provides all of the optional map operations, and permits //{@code null} values and the {@code null} key. publicclassHashMap<K,V> extendsAbstractMap<K,V> implementsMap<K,V>, Cloneable, Serializable{ /* 实现*/ }
HashMap继承于抽象Map类,抽象Map类为Map接口实现了一些操作
1 2
//This implementation provides constant-time performance for the basic //operations ({@code get} and {@code put}),
HasmMap实现了常量级的get和put操作实现。
1 2
//An instance of {@code HashMap} has two parameters that affect its //performance: <i>initial capacity</i> and <i>load factor</i>.
/* * This map usually acts as a binned (bucketed) hash table, but * when bins get too large, they are transformed into bins of * TreeNodes, each structured similarly to those in * java.util.TreeMap. Most methods try to use normal bins, but * relay to TreeNode methods when applicable (simply by checking * instanceof a node). Bins of TreeNodes may be traversed and * used like any others, but additionally support faster lookup * when overpopulated. However, since the vast majority of bins in * normal use are not overpopulated, checking for existence of * tree bins may be delayed in the course of table methods. */
/** * The default initial capacity - MUST be a power of two. */ staticfinalint DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
/** * The maximum capacity, used if a higher value is implicitly specified * by either of the constructors with arguments. * MUST be a power of two <= 1<<30. */ staticfinalint MAXIMUM_CAPACITY = 1 << 30;
/** * The load factor used when none specified in constructor. */ staticfinalfloat DEFAULT_LOAD_FACTOR = 0.75f; /** * 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. */ staticfinalint TREEIFY_THRESHOLD = 8;
/** * 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. */ staticfinalint UNTREEIFY_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. */ staticfinalint MIN_TREEIFY_CAPACITY = 64;
publicfinal V setValue(V newValue){ V oldValue = 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; } }
1 2 3 4 5 6 7 8 9 10 11
staticfinalclassTreeNode<K,V> extendsLinkedHashMap.Entry<K,V> { TreeNode<K,V> parent; // red-black tree links TreeNode<K,V> left; TreeNode<K,V> right; TreeNode<K,V> prev; // needed to unlink next upon deletion boolean red; TreeNode(int hash, K key, V val, Node<K,V> next) { super(hash, key, val, next); } ... }
/** * Returns x's Class if it is of the form "class C implements * Comparable<C>", else null. */ static Class<?> comparableClassFor(Object x) { if (x instanceof Comparable) { Class<?> c; Type[] ts, as; ParameterizedType p; if ((c = x.getClass()) == String.class) // bypass checks return c; if ((ts = c.getGenericInterfaces()) != null) { for (Type t : ts) { if ((t instanceof ParameterizedType) && ((p = (ParameterizedType) t).getRawType() == Comparable.class) && (as = p.getActualTypeArguments()) != null && as.length == 1 && as[0] == c) // type arg is c return c; } } } returnnull; }
/** * Returns k.compareTo(x) if x matches kc (k's screened comparable * class), else 0. */ @SuppressWarnings({"rawtypes","unchecked"})// for cast to Comparable staticintcompareComparables(Class<?> kc, Object k, Object x){ return (x == null || x.getClass() != kc ? 0 : ((Comparable)k).compareTo(x)); }
/** * Returns a power of two size for the given target capacity. 检查所传的参数是否为2的幂次方,且不能为负数(负数变为1),且不能超过常量MAXIMUM_CAPACITY(超过变为MAXIMUM_CAPACITY),如果不为2的幂次方,将其变为,比cap大的最小的2的幂次方的值 */ staticfinalinttableSizeFor(int cap){ int n = -1 >>> Integer.numberOfLeadingZeros(cap - 1); return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1; }
/** * 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;
/** * Holds cached entrySet(). Note that AbstractMap fields are used * for keySet() and values(). */ transient Set<Map.Entry<K,V>> entrySet;
/** * The number of key-value mappings contained in this map. */ transientint size;
/** * The number of times this HashMap has been structurally modified * Structural modifications are those that change the number of mappings in * the HashMap or otherwise modify its internal structure (e.g., * rehash). This field is used to make iterators on Collection-views of * the HashMap fail-fast. (See ConcurrentModificationException). */ transientint modCount;
threshold 当size>threhold时变成红黑树。
加载因子,默认0.75
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/** * The next size value at which to resize (capacity * load factor). * * @serial */ // (The javadoc description is true upon serialization. // Additionally, if the table array has not been allocated, this // field holds the initial array capacity, or zero signifying // DEFAULT_INITIAL_CAPACITY.) int threshold;
/** * The load factor for the hash table. * * @serial */ finalfloat loadFactor;
/** * Constructs an empty {@code HashMap} with the specified initial * capacity and load factor. * * @param initialCapacity the initial capacity * @param loadFactor the load factor * @throws IllegalArgumentException if the initial capacity is negative * or the load factor is nonpositive */ publicHashMap(int initialCapacity, float loadFactor){ if (initialCapacity < 0) thrownew IllegalArgumentException("Illegal initial capacity: " + initialCapacity); if (initialCapacity > MAXIMUM_CAPACITY) initialCapacity = MAXIMUM_CAPACITY; if (loadFactor <= 0 || Float.isNaN(loadFactor)) thrownew IllegalArgumentException("Illegal load factor: " + loadFactor); this.loadFactor = loadFactor; this.threshold = tableSizeFor(initialCapacity); }
/** * Constructs an empty {@code HashMap} with the specified initial * capacity and the default load factor (0.75). * * @param initialCapacity the initial capacity. * @throws IllegalArgumentException if the initial capacity is negative. */ publicHashMap(int initialCapacity){ this(initialCapacity, DEFAULT_LOAD_FACTOR); }
/** * Constructs an empty {@code HashMap} with the default initial capacity * (16) and the default load factor (0.75). */ publicHashMap(){ this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted }
/** * Constructs a new {@code HashMap} with the same mappings as the * specified {@code Map}. The {@code HashMap} is created with * default load factor (0.75) and an initial capacity sufficient to * hold the mappings in the specified {@code Map}. * * @param m the map whose mappings are to be placed in this map * @throws NullPointerException if the specified map is null */ publicHashMap(Map<? extends K, ? extends V> m){ this.loadFactor = DEFAULT_LOAD_FACTOR; putMapEntries(m, false); }
/** * Implements Map.putAll and Map constructor. * * @param m the map * @param evict false when initially constructing this map, else * true (relayed to method afterNodeInsertion). */ finalvoidputMapEntries(Map<? extends K, ? extends V> m, boolean evict){ int s = m.size(); if (s > 0) { if (table == null) { // pre-size float ft = ((float)s / loadFactor) + 1.0F; int t = ((ft < (float)MAXIMUM_CAPACITY) ? (int)ft : MAXIMUM_CAPACITY); if (t > threshold) threshold = tableSizeFor(t); } elseif (s > threshold) resize(); for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) { K key = e.getKey(); V value = e.getValue(); putVal(hash(key), key, value, false, evict); } } }
/** 调用putVal方法,设置值或更新值 * @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 {@code key}, or * {@code null} if there was no mapping for {@code key}. * (A {@code null} return can also indicate that the map * previously associated {@code null} with {@code key}.) */ public V put(K key, V value){ return putVal(hash(key), key, value, false, true); }
/** * @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)//如果table为空,resize一下 n = (tab = resize()).length; if ((p = tab[i = (n - 1) & hash]) == null) //如果当前table中(n - 1) & hash位置为空,则直接插入 tab[i] = newNode(hash, key, value, null); else { //如果不为空,找到key的那个entry Node<K,V> e; K k; if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k))))//先判断第一个 e = p; //然后往下判断 elseif (p instanceof TreeNode) //如果是Tree实现的,调用树的putTreeVal()方法 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; } if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) break; p = e; } } if (e != null) { //查找后存在该点,更新值返回oldValue existing mapping for key V oldValue = e.value; if (!onlyIfAbsent || oldValue == null) e.value = value; afterNodeAccess(e); return oldValue; } } //走到这里说明原来table中没有带key的entry ,插入了一个新的,判断是否需要resize() ++modCount; if (++size > threshold) resize(); afterNodeInsertion(evict); returnnull; }
/** * Splits nodes in a tree bin into lower and upper tree bins, * or untreeifies if now too small. Called only from resize; * see above discussion about split bits and indices. * * @param map the map * @param tab the table for recording bin heads * @param index the index of the table being split * @param bit the bit of hash to split on */ finalvoidsplit(HashMap<K,V> map, Node<K,V>[] tab, int index, int bit){ TreeNode<K,V> b = this; // Relink into lo and hi lists, preserving order TreeNode<K,V> loHead = null, loTail = null; TreeNode<K,V> hiHead = null, hiTail = null; int lc = 0, hc = 0; for (TreeNode<K,V> e = b, next; e != null; e = next) { next = (TreeNode<K,V>)e.next; e.next = null; if ((e.hash & bit) == 0) { if ((e.prev = loTail) == null) loHead = e; else loTail.next = e; loTail = e; ++lc; } else { if ((e.prev = hiTail) == null) hiHead = e; else hiTail.next = e; hiTail = e; ++hc; } }
if (loHead != null) { if (lc <= UNTREEIFY_THRESHOLD) tab[index] = loHead.untreeify(map); else { tab[index] = loHead; if (hiHead != null) // (else is already treeified) loHead.treeify(tab); } } if (hiHead != null) { if (hc <= UNTREEIFY_THRESHOLD) tab[index + bit] = hiHead.untreeify(map); else { tab[index + bit] = hiHead; if (loHead != null) hiHead.treeify(tab); } } }