目录
一、get()方法的执行流程
二、get()方法的源码
三、对比JDK1.7的get()方法源码
3.1 JDK1.7的get()方法执行流程
3.2 JDK1.7的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; }
/** * 源码分析 */ 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的区别