/** * The table, resized as necessary. Length MUST Always be a power of two. */ // 存放Entry的数组,大小必须是2的幂 transient Entry<K,V>[] table = (Entry<K,V>[]) EMPTY_TABLE;
/** * The next size value at which to resize (capacity * load factor). * @serial */ // If table == EMPTY_TABLE then this is the initial capacity at which the // table will be created when inflated. int threshold; // threshold = capacity * load factor,是需要扩展容量时的容量大小
/** * 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) { // 如果数组为空,则初始化数组大小 if (table == EMPTY_TABLE) { inflateTable(threshold); } // 如果key为null,单独调用putForNullKey(value) if (key == null) return putForNullKey(value); // 计算key的hash并根据hash和table的长度计算出数组下标i inthash= hash(key); inti= indexFor(hash, table.length);
// 获取对应下标的链表,判断是否有key值相同的Entry,如果有就使用新值替换并返回oldValue for (Entry<K,V> e = table[i]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { VoldValue= e.value; e.value = value; e.recordAccess(this); return oldValue; } }
/** * Adds a new entry with the specified key, value and hash code to * the specified bucket. It is the responsibility of this * method to resize the table if appropriate. * * Subclass overrides this to alter the behavior of put method. */ voidaddEntry(int hash, K key, V value, int bucketIndex) { // 如果当前size大于threshold且新下标对应位置有值,则需要扩展数组容量,进行resize if ((size >= threshold) && (null != table[bucketIndex])) { // resize,容量double resize(2 * table.length); hash = (null != key) ? hash(key) : 0; // 重新计算数组下标 bucketIndex = indexFor(hash, table.length); }
/** * Rehashes the contents of this map into a new array with a * larger capacity. This method is called automatically when the * number of keys in this map reaches its threshold. * * If current capacity is MAXIMUM_CAPACITY, this method does not * resize the map, but sets threshold to Integer.MAX_VALUE. * This has the effect of preventing future calls. * * @param newCapacity the new capacity, MUST be a power of two; * must be greater than current capacity unless current * capacity is MAXIMUM_CAPACITY (in which case value * is irrelevant). */ voidresize(int newCapacity) { // 超过了最大容量则放弃扩容 Entry[] oldTable = table; intoldCapacity= oldTable.length; if (oldCapacity == MAXIMUM_CAPACITY) { threshold = Integer.MAX_VALUE; return; }
/** * Like addEntry except that this version is used when creating entries * as part of Map construction or "pseudo-construction" (cloning, * deserialization). This version needn't worry about resizing the table. * * Subclass overrides this to alter the behavior of HashMap(Map), * clone, and readObject. */ voidcreateEntry(int hash, K key, V value, int bucketIndex) { Entry<K,V> e = table[bucketIndex]; table[bucketIndex] = newEntry<>(hash, key, value, e); size++; }
/** * Transfers all entries from current table to newTable. */ voidtransfer(Entry[] newTable, boolean rehash) { intnewCapacity= newTable.length; for (Entry<K,V> e : table) { while(null != e) { Entry<K,V> next = e.next; if (rehash) { e.hash = null == e.key ? 0 : hash(e.key); } inti= indexFor(e.hash, newCapacity); e.next = newTable[i]; newTable[i] = e; e = next; } } }