/** * 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; inth= 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; } elseif (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; } } returnnull; }
/** * 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; }
/* * 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") staticfinal <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); }