ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

HashMap之get()剖析

2019-08-07 20:03:31  阅读:152  来源: 互联网

标签:&& hash HashMap get 哈希 剖析 key null first


上次我们已经剖析了get()方法,这次来看看put()方法。

1.HashMap的get()方法剖析:

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

可见,也是将key值进行hash()之后,找到对应的桶数组,再调用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) {
            //若在一个桶中,并且当前索引位置的key值与要查找的key值相等
            //说明找到了,返回该值
            if (first.hash == hash && 
                ((k = first.key) == key || (key != null && key.equals(k))))
                return first;
                //若key值不相同,且还有元素
            if ((e = first.next) != null) {
                //如果此时已经树化,则调用红黑树的getTreeNode()查找
                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);
            }
        }
        //若找不到则返回null
        return null;
    }

2.get()方法流程总结:

  • 首先判断桶数组是否为空,若为空直接返回null。
  • 若桶数组不为空,则计算索引,查看当前索引是否有元素,若有元素,查看key值是否相同。若key值相同,则返回该节点。
  • 若key值不相同,则继续查找,先判断是否树化,若已经树化,则调用红黑树的getTreeNode()进行查找。
  • 若没有树化,则从前往后遍历链表,找到了则返回节点,找不到则返回null。

3.HashMap源码剖析总结:

  • 为什么我们不用hashCode()方法计算的出来的hash值作为桶下标呢?
    因为hashCode()计算出来的hash值太大,需要大量的存储空间;而且这样哈希表就跟普通的数组差不多。

  • 为什么我们要保证哈希表的长度为2^n?
    一方面是为了保证哈希表中所有的元素都被访问到,一定程度上避免哈希碰撞;
    一方面是为了提高运算速度。
    当我们计算元素在哈希表中的索引下标时,采用 i = hash&(n-1),假如我们此时的n为8,则(n-1)=7=0111,就保证了在0-7的范围内,不会发生哈希碰撞,因为此时的i的相与结果完全取决于我们计算出来的hash值。

  • 为什么在hash()中计算桶下标要进行(h>>>16)?
    这样保留了高16位,使得高低16位都参与异或运算,降低了哈希冲突的概率。

4.树化的条件:

  • 当前桶中的链表长度>=8,并且哈希表的长度>=64时,会树化,否则只是进行简单的扩容。
  • 加入红黑树是为了提高由于链表过长而造成的查询效率降低,将时间复杂度由O(n)提升为O(logn)。

5.扩容的条件:当桶数组的容量>12时进行扩容。

6.解树化的条件:当红黑树的节点个数<=6时,会将红黑树转为链表。

标签:&&,hash,HashMap,get,哈希,剖析,key,null,first
来源: https://blog.csdn.net/qq_43574339/article/details/98777721

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有