上一篇我们讲了HashMap的put方法,这篇讲解get方法。
public V get(Object key) {
Node<K,V> e;
return (e = getNode(hash(key), key)) == null ? null : e.value;
}
可以看到get方法里面调用了getNode()方法
final Node<K,V> getNode(int hash, Object key) {
//tab数组, first数组的元素或者链表的第一个节点,e当前节点, n数组大小, k节点的键
Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
//判断数组不为空并且key所在的位置不为空
if ((tab = table) != null && (n = tab.length) > 0 &&
(first = tab[(n - 1) & hash]) != null) {
//如果数组的元素或者链表的第一个节点的key与传进来的key相匹配,返回first
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) //如果时红黑树,调用getTreeNode(hash, key)
return ((TreeNode<K,V>)first).getTreeNode(hash, key);
//不是红黑树,遍历链表
do {
//比较key
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
return e;
} while ((e = e.next) != null);
}
}
return null;
}
getNode(int hash, Object key)有两个参数,第一个时key的hash值,第二个时key。 首选判断数组是否为空,如果为空,则放回null, 如果数组不为空,根据key的hash值计算出key在数组中的位置,当前位置为null,则返回null,否则判断两者的key是否相等,相等返回当前节点。不相等,如果是链表进行do-while循环,比较每一个节点的key,相等则返回,如果是红黑树,调用getTreeNode(hash, key)。
final TreeNode<K,V> getTreeNode(int h, Object k) {
return ((parent != null) ? root() : this).find(h, k, null);
}
如果parent != null返回包含这个节点的树的根否则返回this,其实就是找到树的根节点,然后调用find方法遍历树,根据key找到对应的树节点
final TreeNode<K,V> find(int h, Object k, Class<?> kc) {
TreeNode<K,V> p = this;
do {
//局部变量
int ph, dir; K pk;
TreeNode<K,V> pl = p.left, pr = p.right, q;
if ((ph = p.hash) > h) //key的hash值小于当前树节点的hash值
p = pl; //将左孩子赋值给p,遍历左树
else if (ph < h) //key的hash值大于当前树节点的hash值
p = pr; //将右孩子赋值给p,遍历右树
//key匹配则返回当前树节点
else if ((pk = p.key) == k || (k != null && k.equals(pk)))
return p;
else if (pl == null) //如果当前节点的左孩子为空,则将当前节点的右孩子赋值给p,遍历右树
p = pr;
else if (pr == null)
p = pl;
//如果kc不等于null或者(key实现了Comparable接口并且key通过compare比较之后的值不等于0)
else if ((kc != null ||
(kc = comparableClassFor(k)) != null) &&
(dir = compareComparables(kc, k, pk)) != 0)
//dir < 0,key不匹配
p = (dir < 0) ? pl : pr;
else if ((q = pr.find(h, k, kc)) != null)
return q;
else
p = pl;
} while (p != null);
return null;
}
红黑树获取对应key的值,采用了二分查找,key的hash值大于根节点遍历右子树,小于则遍历左子树。使用了两种比较方法,一种是==和equals匹配,另一种是通过比较器Comparable进行匹配。