参考文章:JDK1.8 HashMap源码分析,感谢原作者
下面是一些主要方法的简单分析:
1、hash()
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
该方法的作用是根据要添加元素的key值,计算得到hash值,根据hash值再计算(n-1)&hash
(n为数组长度)找到该元素将要被添加到数组的哪个位置
2、put()
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict) {
Node<K,V>[] tab; //可以理解为哈希表的数组
Node<K,V> p; //数组中的元素,成员变量为: hash,K,V,nextNode
int n, i;//n: Node数组长度,i:数组下标
/*下面是添加元素的过程*/
//(一)初始化tab,这里调用了扩容方法resize(),扩容后的长度为n
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
//(二)根据hash值找到要添加元素在数组中的位置(下标i),如果此时该位置为空,直接添加
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
//(三)该位置不为空时的情况
else {
Node<K,V> e;
K k;
//(3.1)判断添加元素的hash值和key是否与该位置元素的相同,如果都相同则判定为同一key,将p赋值给e
if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k))))
e = p;
//(3.2)如果key不同,判断当前元素为TreeNode(红黑树节点)的实例,即当前数组位置存放的红黑树,添加元素到红黑树
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
//(3.2)当前数组位置存放的是链表,添加到链表
else {
//找到链表尾部的次数,计算链表的长度
for (int binCount = 0; ; ++binCount) {
//找到链表的结尾
if ((e = p.next) == null) {
//将要添加的节点添加到尾部
p.next = newNode(hash, key, value, null);
//判断链表节点个数是否大于TREEIFY_THRESHOLD,大于转化为红黑树
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash);
break;
}
//判断链表中结点的key值与插入的元素的key值是否相等
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
//当e不为null时,说明原map中已存在元素的key以及hash值与要添加的元素相等,此时e为已存在元素
if (e != null) { // existing mapping for key
//接收旧的value值
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
//将新值的value值赋值给已存在元素的value
afterNodeAccess(e);
//返回原来的value值,即添加相同key值的元素时,put方法更新map中元素value,返回原来的value
return oldValue;
}
}
++modCount;
//扩容操作
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}
3、get()
public V get(Object key) {
Node<K,V> e;
return (e = getNode(hash(key), key)) == null ? null : e.value;
}
final Node<K,V> getNode(int hash, Object key) {
Node<K,V>[] tab;
Node<K,V> first, e;
int n;
K k;
//根据key获取hash值找到桶的位置
if ((tab = table) != null && (n = tab.length) > 0 &&
(first = tab[(n - 1) & hash]) != null) {
//第一个元素即为要找的元素
if (first.hash == hash && // always check first node
((k = first.key) == key || (key != null && key.equals(k))))
return first;
//第一个元素不是
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;
}