/** * The default initial capacity - MUST be a power of two. * 默认table大小,为16 */ 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. * table最大长度,为1,073,741,824 */ 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. * table达到这个长度时才可以树化 */ staticfinalint MIN_TREEIFY_CAPACITY = 64;
/** * 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.) * 哈希表,什么时候初始化?第一次put的时候 */ 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). * 哈希表结构变化次数:put已有的key不会造成modCount变化 */ transientint modCount;
/** * The next size value at which to resize (capacity * load factor). * 触发resize()扩容的阈值,当元素个数大于这个值时,触发扩容 * @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. * 负载因子:threshold = capacity * loadFactor,其中capacity是哈希表数组的长度 * @serial */ finalfloat loadFactor;
c. 构造方法
一共4个构造方法
new HashMap();
new HashMap(int initialCapacity);
new HashMap(int initialCapacity, float 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 * initialCapacity:初始哈希表大小,可以为0 * loadFactor:负载因子,必须大于0 */ publicHashMap(int initialCapacity, float loadFactor){ // 判断传入的initialCapacity是否异常,其取值必须大于且小于MAXIMUM_CAPACITY(1 << 30) if (initialCapacity < 0) thrownew IllegalArgumentException("Illegal initial capacity: " + initialCapacity); if (initialCapacity > MAXIMUM_CAPACITY) initialCapacity = MAXIMUM_CAPACITY; // load factor必须大于0 if (loadFactor <= 0 || Float.isNaN(loadFactor)) thrownew IllegalArgumentException("Illegal load factor: " + loadFactor); this.loadFactor = loadFactor; // 此处有个针对threshold的处理方法,将其转为最小的大于initialCapacity且为2的幂次方的数 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). * 最常用的方法,只对load factor进行了设置,threshold在第一次put时设置,具体是在resize()方法中 */ 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); }
d. tableSizeFor(int)方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/** * Returns a power of two size for the given target capacity. * 返回大于等于传入的数且为2的幂的数 */ staticfinalinttableSizeFor(int cap){ // 减1后,n的非符号不为0的最高位一定小于或等于cap的 int n = cap - 1; // 无符号右移1位 n |= n >>> 1; n |= n >>> 2; n |= n >>> 4; n |= n >>> 8; n |= n >>> 16; return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1; }
/** * 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 * {@code k} to a value {@code v} such that {@code (key==null ? k==null : * key.equals(k))}, then this method returns {@code v}; otherwise * it returns {@code null}. (There can be at most one such mapping.) * * <p>A return value of {@code 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 {@code null}. * The {@link #containsKey containsKey} operation may be used to * distinguish these two cases. * * @see #put(Object, Object) */ public V get(Object key){ Node<K,V> e; return (e = getNode(hash(key), key)) == null ? null : e.value; }
/** * 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>.) * * 将键值对插入hashMap */ public V put(K key, V value){ return putVal(hash(key), key, value, false, true); }