### get 这次先从get方法开始看起,get是读操作,读操作是无锁的。 ```java /** * 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.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 necessarily * 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} method * may be used to distinguish these two cases. * * @see #put(Object, Object) */ public V get(Object key) { Node<K,V>[] tab; Node<K,V> e, p; int n, eh; K ek; int h = spread(key.hashCode()); // 1. 计算hash值,并定位到桶数组中的位置 if ((tab = table) != null && (n = tab.length) > 0 && (e = tabAt(tab, (n - 1) & h)) != null) { // 2. 遍历链表,查找key对应的节点 if ((eh = e.hash) == h) { if ((ek = e.key) == key || (ek != null && key.equals(ek))) return e.val; } else if (eh < 0) return (p = e.find(h, key)) != null ? p.val : null; while ((e = e.next) != null) { if (e.hash == h && ((ek = e.key) == key || (ek != null && key.equals(ek)))) return e.val; } } return null; }
/** * Spreads (XORs) higher bits of hash to lower and also forces top * bit to 0. 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. * * 将哈希值的高位通过异或运算(XOR)传播到低位,并强制最高位为0。 * 由于哈希表的容量总是2的幂次方,只有低位参与桶索引的计算, * 如果哈希值只在高位不同,则会发生碰撞。通过这种方式将高位信息混合到低位, * 可以减少碰撞,提高哈希分布的均匀性。 * 这种做法在速度、实用性和位扩散质量之间做了权衡。 * 由于很多哈希集合本身分布较好,且对于大量碰撞会用红黑树处理, * 所以这里只做了简单的异或操作,既能降低碰撞,也能让高位信息参与索引计算。 */ staticfinalintspread(int h) { return (h ^ (h >>> 16)) & HASH_BITS; }
#### tabAt ```java /* * Atomic access methods are used for table elements as well as * elements of in-progress next table while resizing. All uses of * the tab arguments must be null checked by callers. All callers * also paranoically precheck that tab's length is not zero (or an * equivalent check), thus ensuring that any index argument taking * the form of a hash value anded with (length - 1) is a valid * index. Note that, to be correct wrt arbitrary concurrency * errors by users, these checks must operate on local variables, * which accounts for some odd-looking inline assignments below. * Note that calls to setTabAt always occur within locked regions, * and so require only release ordering. * * 原子访问方法用于table元素以及扩容时的next table元素。 * 所有tab参数的使用都需要调用方进行null检查。 * 调用方还会偏执地预先检查tab的长度不为0,确保(hash & (length-1))形式的索引是有效的。 * 这些检查必须基于局部变量,以防止并发错误。 * setTabAt方法的调用总是在加锁区域内,因此只需要release语义。 */ @SuppressWarnings("unchecked") static final <K,V> Node<K,V> tabAt(Node<K,V>[] tab, int i) { // 通过Unsafe的getReferenceAcquire方法原子性地获取tab数组指定位置的元素 return (Node<K,V>)U.getReferenceAcquire(tab, ((long)i << ASHIFT) + ABASE); }
/** * 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.) * * 哈希表,首次使用时初始化,并在必要时扩容。分配时长度总是2的幂。 * (某些操作允许长度为0,以支持目前不需要的引导机制。) */ transient Node<K,V>[] table;
/** * Holds cached entrySet(). Note that AbstractMap fields are used * for keySet() and values(). * * 缓存entrySet(),注意AbstractMap的字段用于keySet()和values()。 */ transient Set<Map.Entry<K,V>> entrySet;
/** * The number of key-value mappings contained in this map. * * 当前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). * * HashMap结构性修改的次数。结构性修改指改变映射数量或内部结构(如rehash)。 * 该字段用于让Collection视图的迭代器快速失败(fail-fast)。 * (参见ConcurrentModificationException) */ transientint modCount;
/** * 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.) // (Javadoc描述在序列化时有效。如果table数组未分配,该字段保存初始容量,0表示DEFAULT_INITIAL_CAPACITY。) int threshold;
/** * The load factor for the hash table. * * 哈希表的负载因子。 * * @serial */ finalfloat loadFactor;
构造器
无参构造器
这个也是我们最常用的一个构造器,仅仅指定了负载因子,其他的字段都使用默认值。
1 2 3 4 5 6 7
/** * 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 }
而负载因子是0.75,这个值在时间和空间的权衡之下的一个不错的选择。
1 2 3 4 5 6
/** * The load factor used when none specified in constructor. */ staticfinalfloatDEFAULT_LOAD_FACTOR=0.75f;
/** * 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 {@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}.) * 返回与key关联的前一个值,如果没有映射则返回null。 * (返回null也可能表示该映射之前将null与key关联。) */ public V put(K key, V value) { // 调用putVal方法,插入或更新键值对 return putVal(hash(key), key, value, false, true); }
/** * 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. * * 计算key的hashCode,并将高位的hash通过异或运算混合到低位。 * 因为哈希表的长度总是2的幂,只有低位参与寻址,如果高位不同而低位相同会导致哈希冲突。 * 通过将高位与低位异或,可以让高位的信息参与寻址,减少哈希冲突。 */ staticfinalinthash(Object key) { int h; // 如果key为null,返回0,否则返回hashCode与其高16位右移后异或的结果 return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); }
/** * 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) * * 返回指定key对应的value,如果没有该key的映射则返回null。 * 注意,返回null不一定表示没有该key的映射,也可能是该key被显式映射为null。 * 可以通过containsKey方法区分这两种情况。 */ public V get(Object key) { Node<K,V> e; return (e = getNode(key)) == null ? null : e.value; }
/** * Shared empty array instance used for empty instances. */ privatestaticfinal Object[] EMPTY_ELEMENTDATA = {};
/** * Shared empty array instance used for default sized empty instances. We * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when * first element is added. * 用于默认容量空实例的共享空数组实例。 * 我们将其与 EMPTY_ELEMENTDATA 区分开来,以便在添加第一个元素时知道应该扩容多少。 */ privatestaticfinal Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/** * The array buffer into which the elements of the ArrayList are stored. * The capacity of the ArrayList is the length of this array buffer. Any * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA * will be expanded to DEFAULT_CAPACITY when the first element is added. * ArrayList用于存储元素的数组缓冲区。ArrayList的容量即为该数组的长度。 * 任何elementData为DEFAULTCAPACITY_EMPTY_ELEMENTDATA的空ArrayList, * 在添加第一个元素时会扩容到DEFAULT_CAPACITY。 */ transient Object[] elementData; // non-private to simplify nested class access
/** * The size of the ArrayList (the number of elements it contains). * ArrayList的实际元素个数。 * * @serial */ privateint size;
/** * Constructs a list containing the elements of the specified * collection, in the order they are returned by the collection's * iterator. * * @param c the collection whose elements are to be placed into this list * @throws NullPointerException if the specified collection is null */ publicArrayList(Collection<? extends E> c) { Object[] a = c.toArray(); if ((size = a.length) != 0) { if (c.getClass() == ArrayList.class) { elementData = a; } else { elementData = Arrays.copyOf(a, size, Object[].class); } } else { // replace with empty array. elementData = EMPTY_ELEMENTDATA; } }
/** * Copies the specified array, truncating or padding with nulls (if necessary) * so the copy has the specified length. For all indices that are * valid in both the original array and the copy, the two arrays will * contain identical values. For any indices that are valid in the * copy but not the original, the copy will contain {@code null}. * Such indices will exist if and only if the specified length * is greater than that of the original array. * The resulting array is of the class {@code newType}. * * 复制指定的数组,如有必要会截断或用 null 填充,使复制后的数组具有指定长度。 * 原数组和新数组中索引都有效的位置,值完全相同。 * 新数组中多出来的部分(如果有)会用 null 填充。 * 只有当 newLength 大于原数组长度时才会出现这种情况。 * 返回的新数组类型为 newType。 * * @param <T> the class of the objects in the returned array * 返回数组中对象的类型 * @param <U> the class of the objects in the original array * 原数组中对象的类型 * @param original the array to be copied * 要复制的原数组 * @param newLength the length of the copy to be returned * 返回的新数组长度 * @param newType the class of the copy to be returned * 返回的新数组类型 * @return a copy of the original array, truncated or padded with nulls * to obtain the specified length * 复制后的新数组,长度为 newLength * @throws NegativeArraySizeException if {@code newLength} is negative * 如果 newLength 为负数,抛出异常 * @throws NullPointerException if {@code original} is null * 如果 original 为 null,抛出异常 * @throws ArrayStoreException if an element copied from * {@code original} is not of a runtime type that can be stored in * an array of class {@code newType} * 如果原数组元素类型与新数组类型不兼容,抛出异常 * @since 1.6 */ @IntrinsicCandidate publicstatic <T,U> T[] copyOf(U[] original, int newLength, Class<? extendsT[]> newType) { @SuppressWarnings("unchecked") // 判断目标类型是否为 Object[],是则直接 new,否则用反射创建 T[] copy = ((Object)newType == (Object)Object[].class) ? (T[]) newObject[newLength] : (T[]) Array.newInstance(newType.getComponentType(), newLength); // 复制原数组内容到新数组,长度为原数组和新数组长度的较小值 System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); return copy; }
公共方法
trimToSize
该方法主要是将内部数组容量缩减为当前元素数量以释放多余内存。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
/** * Trims the capacity of this {@code ArrayList} instance to be the * list's current size. An application can use this operation to minimize * the storage of an {@code ArrayList} instance. */ publicvoidtrimToSize() { modCount++; if (size < elementData.length) { elementData = (size == 0) ? EMPTY_ELEMENTDATA : Arrays.copyOf(elementData, size); } }
/** * Increases the capacity of this {@code ArrayList} instance, if * necessary, to ensure that it can hold at least the number of elements * specified by the minimum capacity argument. * * 如有必要,增加此ArrayList实例的容量,以确保它至少能容纳minCapacity指定数量的元素。 * * @param minCapacity the desired minimum capacity * 所需的最小容量 */ publicvoidensureCapacity(int minCapacity) { if (minCapacity > elementData.length && !(elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA && minCapacity <= DEFAULT_CAPACITY)) { modCount++; grow(minCapacity); } }
/** * Increases the capacity to ensure that it can hold at least the * number of elements specified by the minimum capacity argument. * * 增加容量以确保至少能容纳minCapacity指定数量的元素。 * * @param minCapacity the desired minimum capacity * 所需的最小容量 * @throws OutOfMemoryError if minCapacity is less than zero * 如果minCapacity小于0会抛出内存溢出错误 */ private Object[] grow(int minCapacity) { // 获取老容量,也就是当前容量 intoldCapacity= elementData.length; // 如果当前容量大于0 或者 元素不是默认构造器的占位符DEFAULTCAPACITY_EMPTY_ELEMENTDATA if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { intnewCapacity= ArraysSupport.newLength(oldCapacity, minCapacity - oldCapacity, /* minimum growth 最小增长量 */ oldCapacity >> 1/* preferred growth 推荐增长量 */); // 复制原数组到新容量 returnelementData= Arrays.copyOf(elementData, newCapacity); } else { // 如果原数组为空,则分配默认容量或minCapacity中较大的值 returnelementData=newObject[Math.max(DEFAULT_CAPACITY, minCapacity)]; } }