HashMap get方法源码
get方法图示:
get方法源码:
get方法
/**
* 这是一个比较重要的一个方法(get和put方法都是HashMap操作比较重要的方法)
* 根据键key,获取对应的值
*/
public V get(Object key) {
Node<K,V> e;
return (e = getNode(hash(key), key)) == null ? null : e.value;
}
getNode方法
/**
* getNode(hash(key), key)
* 通过key的hash值和key获取节点Node
*/
final Node<K,V> getNode(int hash, Object key) {
Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
//将table赋值给tab变量,将table的length赋值给n。tab[(n - 1) & hash]计算存放在数组table中的位置赋值给first。
//判断该槽位是否为null. first为该槽位的第一个Node。
if ((tab = table) != null && (n = tab.length) > 0 &&
(first = tab[(n - 1) & hash]) != null) {
//总是先判断槽位的第一Node是否是我们要获取的Node如果是则直接返回。
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;//否则返回null
}
getTreeNode方法
/**
* 获取红黑树的指定节点
*/
final TreeNode<K,V> getTreeNode(int h, Object k) {
// 从根节点开始查询,判断parent是否为null,为null说明当前节点就是
// 跟根节点否则调用root()方法需找根节点然后调用find()方法查找节点。
return ((parent != null) ? root() : this).find(h, k, null);
}
root方法
/**
* 根据当前节点获取根节点
*/
final TreeNode<K,V> root() {
//从当前节点开始向上找当前节点的parent
for (TreeNode<K,V> r = this, p;;) {
//如果当前节点的parent == null则表示寻找到根节点则返回根节点
if ((p = r.parent) == null)
return r;
//否则将当前节点的父节点赋值给r继续遍历。
r = p;
}
}
find方法
/**
* 这个方法是TreeNode类的一个实例方法,调用该方法的也就是一个TreeNode对象,
* 该对象就是树上的某个节点,以该节点作为根节点,查找其所有子孙节点,
* 看看哪个节点能够匹配上给定的键对象
* h k的hash值
* k 要查找的对象
* kc k的Class对象,该Class应该是实现了Comparable<K>的,否则应该是null,参见:
*/
final TreeNode<K,V> find(int h, Object k, Class<?> kc) {
TreeNode<K,V> p = this;// 把当前对象赋给p,表示当前节点
do {
int ph, dir; K pk; // 定义当前节点的hash值、方向(左右)、当前节点的键对象
TreeNode<K,V> pl = p.left, pr = p.right, q;// 获取当前节点的左孩子、右孩子。定义一个对象q用来存储并返回找到的对象
if ((ph = p.hash) > h)// 如果当前节点的hash值大于k得hash值h,那么后续就应该让k和左孩子节点进行下一轮比较
p = pl;// p指向左孩子,紧接着就是下一轮循环了
else if (ph < h)// 如果当前节点的hash值小于k得hash值h,那么后续就应该让k和右孩子节点进行下一轮比较
p = pr;// p指向右孩子,紧接着就是下一轮循环了
else if ((pk = p.key) == k || (k != null && k.equals(pk)))// 如果h和当前节点的hash值相同,并且当前节点的键对象pk和k相等(地址相同或者equals相同)
return p;// 返回当前节点
// 执行到这里说明hash比对相同,但是pk和k不相等
else if (pl == null)//如果左节点为空
p = pr;// p指向右孩子,紧接着就是下一轮循环
else if (pr == null)//如果右结点为空
p = pl;// p指向左孩子,紧接着就是下一轮循环
// 如果左右孩子都不为空,那么需要再进行一轮对比来确定到底该往哪个方向去深入对比
// 这一轮的对比主要是想通过comparable方法来比较pk和k的大小
else if ((kc != null ||
(kc = comparableClassFor(k)) != null) &&
(dir = compareComparables(kc, k, pk)) != 0)
p = (dir < 0) ? pl : pr;// dir小于0,p指向右孩子,否则指向右孩子。紧接着就是下一轮循环
// 执行到这里说明无法通过comparable比较 或者 比较之后还是相等
// 从右孩子节点递归循环查找,如果找到了匹配的则返回
else if ((q = pr.find(h, k, kc)) != null)
return q;
else// 如果从右孩子节点递归查找后仍未找到,那么从左孩子节点进行下一轮循环
p = pl;//进入左节点
} while (p != null);
return null;// 未找到,返回null
}
至此get方法及其内部调用的各个方法均讲解完毕。不能在详细了!!!!!!