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

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

两个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()的参与,可见这个静态方法是多么重要

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值