来总结一下HashMap的原理

1.HashMap当中有一个内部类,它叫Node,然后这个Node呢,它其实是实现了Map.Entry接口,这个接口当中有几个抽象的方法和几个具体的方法。其中Map.Entry<K,V>是一个泛型的元组。

2.Map.Entry接口中有如下抽象方法:

  • getKey()
  • getValue()
  • setValue()
  • hashCode()
  • equals

3.Node的私有变量如下:

  • hash
  • key
  • value
  • Next node

其中HashMap的核心是hashcode的生成算法,hashCode的生成算法如下:

 Objects.hashCode(key) ^ Objects.hashCode(value);

它是先通过得到Key和value的hashcode,然后对2个值进行异或操作后得到的值。

其中Object.hashCode是一个native的方法。

    public native int hashCode();

其中Node的equals方法,传入的对象是object,只有当object的类型是map.entry并且,当前对象的key和value都和传入的key,value一致,那样才会返回相等。

下面的这个方法,是计算hash值的方法。它是通过key去计算,然后把拿到的hashcode和它右移16位的结果进行异或操作,具体回头再看为什么,我也不知道。

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

hashMap里面还有一个entrySet的成员变量,它是一个set 的集合,这里面的transient关键字不太懂,回头再看看。

   transient Set<Map.Entry<K,V>> entrySet;

HashMap里面有一个非常重要的方法,叫做putVal()方法。这算是里面最核心的一个方法了,弄懂了这个方法,80%的HashMap相关的知识都能弄懂了

首先是有2个Node的声明,一个是tab,一个是p.

Node<K,V>[] tab; Node<K,V> p; int n, i;

下面我们来解析一下PutVal方法,如果table为空,或者table的长度为0,重置table的长度。

if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;

首先是下面的代码会利用到上面的代码,n得出了一个结果,那就是resize()后的结果,下面的n-1就是“”最后“”一个元素

        if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);

下面的代码就是上面的tabl[x]里面的逻辑,这里面用到了按位与的一个运算:为什么要这么做?不知道。

来做一个小小的补充,这里要先复习一下按位与的结果操作,什么时候获取什么值,如果hash是一个负数,那又是什么情况呢?

(n - 1) & hash

我猜想的是,如果“”找到的“”元素为null,那么新建一个node元素。并且这个node元素的next为空。否则执行else里面的逻辑。

----------------------------------------我是分割线---------------------------------------------

首先putVal方法会去计算这个key的hash值。

首先我觉得要明白hash算法的真谛,网上找的这句话,说得不错:要找到散列为同一个值的两个不同的输入,在计算上是不可能的,所以数据的哈希值可以检验数据的完整性。

当第一次进入putval方法的时候,table是空的,所以肯定要进行一个resize操作,不光是table,连threshold都是0,所有的东西都未能初始化的情况下,这个时候,应该进入如下逻辑:

newCap = DEFAULT_INITIAL_CAPACITY;
newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);

这个时候,newCapicity的话就变成了初始值16,newThr变成了初始化的Threhold,如果是这种情况下的话,就会新建一个长度为16的Node<K,V>[]数组,最后返回newTable,注意,resize操作的返回对象。

   Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];

在下面的例子中,hash值是一个非常大的值,换算成2进制,它是32位长度的一个2进制,用按位与的操作是最快的,因为计算机内部结构就是二进制的。

 if ((p = tab[i = (n - 1) & hash]) == null)

注意!!!它先填充的是tab[10]的内容,也就是说,并没有从0开始填充,这是违背我们直觉的一件事情。

然后让modCount++,

最后,如果负载因子小于size,那么,hashmap会自动扩容。

        if (++size > threshold)
resize();

随后执行afterNodeInsertion方法,这个方法在Hashmap当中是一个空的方法,API里面介绍的是为LinkedHashMap所用,所以这里不再做讨论。还有注意下,如果是新建的hashMap第一次putval,那么它的返回值为null.

要注意一点,新建一个HashMap,它并不是独立存在的,在你把你的key添加进去之前,它还会添加非常多的其他的KEY,也就是我们所说的:系统路径,所以最后得出的结果就是,如果你是一个新的HashMap,那么,你添加了一个KEY,肯定这里面不止一个KEY。

大家可以观察到,当SIZE=13的时候,

其实是自动进入了resize这个方法的,你看我断点都进来了。这就证明了hashmap的自动扩容机制。

那么为什么会有这么多的Node被添加进来呢?原因只有一个,就是我们用idea启动项目的时候,一些类其实是用到了HashMap的,它优于我们调试的时候进入的HashMap,所以刚才大家才会看到那么多的节点被添加到hashMap当中去。

当我把在putVal上的断点去掉以后,就进入了如下代码块,验证了我的猜想。

另外还有一个很有趣现象,我用单元测试,新建了一个HashMap,结果。。。你发现没有,jdk里面已经填充了4项了,原来,我们认为的Hashmap,有多少项,就add多少项的观点其实是错误的!!!

下面我们再来看看如下代码,传入的hash和之前的hash进行对比,这里面可能大家有一些迷糊,当然包括我也看不懂,不过从这里可以获取一个非常重要的信息,这么做的方式就是为了避免一个hashmap钟可能出现“相同”的hash对象,我是这么理解的,如果有高人,可以来解释下为什么这样。

        if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;

下面的代码也很明白了,如果不是上面都 ,那么如果是树节点,那么就执行下面的逻辑,此处不再深究。

  else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);

下面的代码的含义是,如果p.next为空的话,那么新建一个节点,并追加到尾部,这种情况,就是当p指向最后一个节点的时候才会出现的情况。

                for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash);
break;
}
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}

后面的代码有点感觉太难啃了,先暂时就这样吧,今天的HashMap分析得还不太完整,并且不太合理,希望大家能多提宝贵建议。

HashMap原理总结的更多相关文章

  1. ==和equasl、hashmap原理(***)

    public class String01 { public static void main(String[] args) { String a="test"; String b ...

  2. Java基础-hashMap原理剖析

    Java基础-hashMap原理剖析 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任.   一.什么是哈希(Hash) 答:Hash就是散列,即把对象打散.举个例子,有100000条数 ...

  3. Java:HashMap原理与设计缘由

    前言 Java中使用最多的数据结构基本就是ArrayList和HashMap,HashMap的原理也常常出现在各种面试题中,本文就HashMap的设计与设计缘由作出一一讲解,并解答面试常见的一些问题. ...

  4. HashMap原理(二) 扩容机制及存取原理

    我们在上一个章节<HashMap原理(一) 概念和底层架构>中讲解了HashMap的存储数据结构以及常用的概念及变量,包括capacity容量,threshold变量和loadFactor ...

  5. java中HashMap原理?

    参考:https://www.cnblogs.com/yuanblog/p/4441017.html(推荐) https://blog.csdn.net/a745233700/article/deta ...

  6. 2021超详细的HashMap原理分析,面试官就喜欢问这个!

    一.散列表结构 散列表结构就是数组+链表的结构 二.什么是哈希? Hash也称散列.哈希,对应的英文单词Hash,基本原理就是把任意长度的输入,通过Hash算法变成固定长度的输出 这个映射的规则就是对 ...

  7. HashMap原理及源码分析

    HashMap 原理及源码分析 1. 存储结构 HashMap 内部是由 Node 类型的数组实现的.Node 包含着键值对,内部有四个字段,从 next 字段我们可以看出,Node 是一个链表.即数 ...

  8. HashMap原理与优化

    参考文献: HashMap的工作原理 java中HashMap重要性质和优化总结 一.HashMap的基本了解 基本定义:根据源代码的描述可知,HashMap是基于哈希表的Map接口的实现,其包含了M ...

  9. HashMap原理详解

    HashMap 概述 HashMap 是基于哈希表的 Map 接口的非同步实现.此实现提供所有可选的映射操作,并允许使用 null 值和 null 键.此类不保证映射的顺序,特别是它不保证该顺序恒久不 ...

  10. 面试题 HashMap 原理

    HashMap与HashTable的区别 总结: HashMap是用来代替HashTable的类,一般建议使用HashMap.最核心的区别:HashTable的方法是同步的(线程安全),而HashMa ...

随机推荐

  1. POJ 1163 The Triangle【dp+杨辉三角加强版(递归)】

    The Triangle Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 49955   Accepted: 30177 De ...

  2. 在R12下加载Java Bean,配置FORMS_WEB_CONFIG_FILE文件/通过AutoConfig实现Form Server配置文件的修改

    1.定位模版文件$AD_TOP/bin/adtmplreport.sh contextfile=$CONTEXT_FILE target=$FORMS_WEB_CONFIG_FILE以上命令,通过查看 ...

  3. msf

    show exploit show payload msf使用数据库加快搜索,不然每次都等半天 service postgresql startmsfdb reinitmsf > db_rebu ...

  4. 听说 Android 9.0 要禁用 @Hide Api 的调用,你怎么看?

    Android 9.0? Hi,大家好,我是承香墨影! 距离 Android 8.0 发布,已经过了五个月,虽然现在占有率并不高,不过呢,Google 已经着手准备下一版本的 Android 系统. ...

  5. TI-RTOS 之 GPIO中断(按键)

    TI-RTOS 之 GPIO中断(按键) 前面已经用过LED, 定时器,这次来了解GPIO的中断是怎么用的,从CC1310+TI-RTOS的例程可以直接找到相应的例子程序,它的关键是在于要使能中断,也 ...

  6. oracle 数据库——知识点总结(加示例)

    新入oracle数据库,把目前学到的知识点记录下来,可能都比较基础,但还是比较全的,里面的示例都是自己在PL/SQL中跑过的,如果有错误,还望各位大侠指出哈. 创建用户 1.创建用户(使用管理员身份创 ...

  7. HDU 5538 House Building(模拟——思维)

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5538 Problem Description Have you ever played the vi ...

  8. error: Failed dependencies:解决

    error: Failed dependencies:解决 使用rpma安装安装包时,会出现 error: Failed dependencies: 意思是 失败的依赖 解决方法: 在安装包后面加两个 ...

  9. html dl dt dd标签元素语法结构与使用

    dl dt dd认识及dl dt dd使用方法 标签用于定义列表类型标签. dl dt dd目录 dl dt dd介绍 结构语法 dl dt dd案例 dl dt dd总结 一.dl dt dd认识 ...

  10. JS_全

    <script src="jquery-1.9.1.js" type="text/javascript"></script> <s ...