Java教程

【Java集合】HashMap的get()源码详解以及JDK1.7与JDK1.8的区别

本文主要是介绍【Java集合】HashMap的get()源码详解以及JDK1.7与JDK1.8的区别,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

目录

一、get()方法的执行流程

二、get()方法的源码

三、对比JDK1.7的get()方法源码

3.1 JDK1.7的get()方法执行流程

3.2 JDK1.7的get()方法源码


一、get()方法的执行流程

查找主要分为三个步骤:

  1. 根据hash算法定位数组的索引位置,找到key及其第一个元素。
  2. 通过equals方法判断第一个节点是否是我们需要的key,是的话直接返回,不是的话,往后遍历
  3. 判断当前节点的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.7get()方法源码

3.1 JDK1.7get()方法执行流程

3.2 JDK1.7get()方法源码

/**
* 源码分析
*/ 
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的区别

这篇关于【Java集合】HashMap的get()源码详解以及JDK1.7与JDK1.8的区别的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!