ighest bits that would otherwise
* never be used in index calculations because of table bounds.
*/
//计算键。hashCode()并将哈希的高位扩展(XOR)到低位。因为该表使用两个掩码的幂,所以仅在当前掩码之上的位中变化的哈希集将始终发生冲突。(在已知的例子中,有一组浮点键在小表中保持连续的整数。)因此,我们应用了一种将高位的影响向下扩散的变换。比特扩展的速度、效用和质量之间存在权衡。因为许多常见的散列集已经被合理地分布(因此不会从扩展中受益),并且因为我们使用树来处理bin中的大量冲突,我们只需以最便宜的方式对一些移位的位进行异或,以减少系统损失,并合并由于表边界而永远不会用于索引计算的最高位的影响。
// 获取键的hash值,HashMap中键的hash值都是经过处理的,使得平均分布在数组上而不会集中分布在某一位置,jdk1.8使用的是高低位异或(16位)
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
/**
* Implements Map.get and related methods.
*
* @param hash hash for key
* @param key the key
* @return the node, or null if none
*/
//实施映射。get和相关方法。 参数: hash–密钥的哈希 key–钥匙 返回值: 节点,如果没有,则为null
// hash为键的hash值,key为外部传入的键
// 因为初始获得的Hash的值太长了无法直接在数组中使用,所以HashMap使用HashMap使用hash确定元素下标的方式为:hash值与数组长度取余,又因为 任何数 & 2的n次幂 -1 = 任何数 % 2的n次幂,而&运算要比%快,所以HashMap确定数组下标的公式为:hash & n-1,也所以HashMpa中数组长度也必须为2的n次幂.
//
final Node<K,V> getNode(int hash, Object key) {
Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
if ((tab = table) != null && (n = tab.length) > 0 && //判断HashMpa是否为空
(first = tab[(n - 1) & hash]) != null) { //为空则直接返回null
//找到对应数组下标下的链表,判断头节点是否就是要找的元素,是则直接返回头节点
if (first.hash == hash && //always check first node
((k = first.key) == key || (key != null && key.equals(k))))
return first;
//判断链表中是否只有一个元素,是则直接返回null,否则继续向下查询
if ((e = first.next) != null) {
// 判断是否为红黑树,是则使用红黑树方式查找
if (first instanceof TreeNode)
return ((TreeNode<K,V>)first).getTreeNode(hash, key); //不会嘿嘿
// 遍历链表,并挨个对比是否是要找的元素
do {
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
return e;
} while ((e = e.next) != null);
}
}
return null;
}
put添加相关方法和属性
/**
* 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>.)
*/
//将指定值与此映射中的指定键相关联。如果映射之前包含键的映射,则替换旧值。
//参数: key–与指定值关联的键 value–与指定键关联的值
//返回值: 与键关联的前一个值,如果没有键的映射,则为null。(null返回还可以指示映射先前将null与键关联。)
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
/**
* Implements Map.put and related methods.
*
* @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
*/
//实施映射。put和相关方法。
//参数: hash–密钥的哈希 key–钥匙 value–要放置的值 onlyIfAbsent–如果为true,则不更改现有值 evict-如果为false,则表处于创建模式。
//返回值: 上一个值,如果没有则为null
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;
//检查HashMap中是否为空,为空则使用resize初始化,并给n赋值
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
//检查数组下标处是否为空,是则直接赋值((n - 1) & hash 为下标)