目录
一、get()方法的执行流程
查找主要分为三个步骤:
- 根据hash算法定位数组的索引位置,找到key及其第一个元素。
- 通过equals方法判断第一个节点是否是我们需要的key,是的话直接返回,不是的话,往后遍历
- 判断当前节点的next是不是null,如果不是的话,再判断属于哪个类型,如果是红黑树就采用遍历红黑树的方法查找节点,否则就以遍历链表的方式查找。
流程图:
二、get()方法的源码
根据指定的key,查找对应的value值,找不到返回null,后续操作get()方法返回的结果时一定要判断非null,否则会出现空指针异常。
public V get(Object key) {
Node<K,V> e;
return (e = getNode(hash(key), key)) == null ? null : e.value;
}
根据key的hash和key,查找节点。找不到返回null
/**
* Implements Map.get and related methods
*
* @param hash hash for key
* @param key the key
* @return the node, or null if none
*/
final Node<K,V> getNode(int hash, Object key) {
// tab:当前map的数组,first:当前hash对应的索引位置上的节点,e:遍历过程中临时存储的节点,
// n:tab数组的长度,k:first节点的key/遍历链表时遍历到的节点e的key值
Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
// 1.对table进行校验:table不为空 && table长度大于0 &&
// hash对应的索引位置上的节点不为空
if ((tab = table) != null && (n = tab.length) > 0 &&
(first = tab[(n - 1) & hash]) != null) {
// 判断第一个节点是不是要找的元素,比较hash值和key是否和入参的一样,如果一样,直接返回第一个节点
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
return ((TreeNode<K,V>)first).getTreeNode(hash, key);
}
// 前提条件:第一个节点不为null,并且也不是红黑树,而且还有下一个节点,那么该索引位置的元素类型就是链表,从第二个节点开始遍历该链表,
do {
// hash值和key值与入参一致,说明找到要查询的节点,返回节点
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
return e;
} while ((e = e.next) != null);// e指针后移,并且下一个节点不为null则继续遍历,不为null表示没到链表最后
}
}
// 没找到返回null
return null;
}
三、对比JDK1.7的get()方法源码
3.1 JDK1.7的get()方法执行流程
3.2 JDK1.7的get()方法源码
/**
* 源码分析
*/
public V get(Object key) {
// 1. 当key == null时,则到 以哈希表数组中的第1个元素(即table[0])为头结点的链表去寻找对应 key == null的键
if (key == null)
return getForNullKey(); // --> 分析1
// 2. 当key ≠ null时,去获得对应值 -->分析2
Entry<K,V> entry = getEntry(key);
return null == entry ? null : entry.getValue();
}
/**
* 分析1:getForNullKey()
* 作用:当key == null时,则到 以哈希表数组中的第1个元素(即table[0])为头结点的链表去寻找对应 key == null的键
*/
private V getForNullKey() {
// HashMap为空,直接返回null
if (size == 0) {
return null;
}
// 遍历以table[0]为头结点的链表,寻找 key==null 对应的值
for (Entry<K,V> e = table[0]; e != null; e = e.next) {
// 从table[0]中取key==null的value值
if (e.key == null)
return e.value;
}
return null;
}
/**
* 分析2:getEntry(key)
* 作用:当key ≠ null时,去获得对应值
*/
final Entry<K,V> getEntry(Object key) {
// HashMap为空,直接返回null
if (size == 0) {
return null;
}
// 1. 根据key值,通过hash()计算出对应的hash值
int hash = (key == null) ? 0 : hash(key);
// 2. 根据hash值计算出对应的数组下标
// 3. 遍历 以该数组下标的数组元素为头结点的链表所有节点,寻找该key对应的值
for (Entry<K,V> e = table[indexFor(hash, table.length)]; e != null; e = e.next) {
Object k;
// 若 hash值 & key 相等,则证明该Entry = 我们要的键值对
// 通过equals()判断key是否相等
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
return e;
}
return null;
}
相关文章:【Java集合】HashMap的put()源码详解以及JDK1.7与JDK1.8的区别
【Java集合】HashMap的resize()源码详解以及JDK1.7与JDK1.8的区别