欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Java之HashMap源码分析(第五篇:访问元素)

程序员文章站 2024-01-02 13:03:40
0、...

(注意:本文源码基于JDK1.8) 

Java之HashMap源码分析(第五篇:访问元素)

两个get()方法,均可以获取Value对象,我们一起学习一下

 

get(Object)方法分析

    public V get(Object key) {
        Node<K,V> e;
        return (e = getNode(hash(key), key)) == null ? null : e.value;
    }

用于返回指定Key对象对应的Value元素,Value对象即为元素,传入的参数key表示Key对象

1、定义一个局部变量e,它的类型是Node,用于持有返回的结点对象

2、获取Key对象对应的hash值

先调用静态方法hash(),目的是为了得到将Key对象经过二次扰动后的值,称为hash值

3、获取指定Key对象对应的Node对象

调用getNode()方法,将静态方法hash()返回的值与Key对象同时传入了进去,getNode()方法的返回值会赋值给局部变量e

4、判断是否获取到Node对象,并返回给调用方结果

对局部变量e进行判断,为null,说明没有找到Key对象对应的Node对象,此时返回null

如果获取到Node对象,则取出Node对象持有的value,并返回给调用方,此value为元素对象

 

getNode()方法分析

    final Node<K,V> getNode(int hash, Object key) {
        Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
        if ((tab = table) != null && (n = tab.length) > 0 &&
            (first = tab[(n - 1) & hash]) != null) {
            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;
    }

用于根据hash值与Key对象,返回对应的Node对象的方法,传入的参数hash表示Key对象的hash值(二次扰动后的值),传入的参数key表示Key对象

1、创建几个局部变量,用于存储过程值

局部变量tab用于存储HashMap对象持有的底层数组对象

局部变量first用于存储数组桶中的第一个Node对象

局部变量e用于存储单链表遍历过程中的每个Node对象

局部变量n用于存储底层数组对象的容量

局部变量k用于存储Key对象

2、先做三个判断

判断旧数组table是否已经创建

判断旧数组table是否已经长度大于0

判断旧数组某个下标处是否包含有元素(桶地址的计算:通过数组的长度与Key对象经过二次扰动后的hash值进行位与运算而得出)

3、针对下标处的三种情况分别处理

对下标处(桶地址)只有一个元素进行处理:先取出Node对象持有的hash值进行比较,相等的情况下,继续通过Node对象持有的key对象与传入的key对象进行==的比较,如果==是不相等的情况,继续通过key对象的equals()方法进行比较(这是为了照顾Key对象为null的情况,作者写的很巧妙)

对下标处(桶地址)为单链表的情况进行处理:对单链表进行遍历,直到找到匹配的情况

对下标处(桶地址)为红黑树的情况进行处理:当桶中的对象为TreeNode说明为红黑树结构,通过另外一个getTreeNode()方法进行比较

4、上面的三种情况,只要一种符合元素的要求,返回Node对象,否则返回一个null,表示没有匹配的对象

 

静态方法hash()分析

    static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

用于根据Key对象再重新计算出一个hash值的方法,在前文中已经做了分析,此处不再做分析

 

getOrDefault()方法分析

 

    public V getOrDefault(Object key, V defaultValue) {
        Node<K,V> e;
        return (e = getNode(hash(key), key)) == null ? defaultValue : e.value;
    }

用于获取Value对象的方法,特点是可以指定一个参数defaultValue,当通过Key找不到对应Value时,会返回指定的默认值

 

总结

1、HashMap的添加、删除、访问元素,均有静态方法hash()的参与,可见这个静态方法是多么重要

本文地址:https://blog.csdn.net/cadi2011/article/details/104729092

上一篇:

下一篇: