哈希娱乐深入理解Java中的HashMap
哈希游戏作为一种新兴的区块链应用,它巧妙地结合了加密技术与娱乐,为玩家提供了全新的体验。万达哈希平台凭借其独特的彩票玩法和创新的哈希算法,公平公正-方便快捷!万达哈希,哈希游戏平台,哈希娱乐,哈希游戏本文主要说的是jdk1.8版本中的实现。而1.8中HashMap是数组+链表+红黑树实现的,大概如下图所示。后面还是主要介绍Hash Map中主要的一些成员以及方法原理。
那么上述图示中的结点Node具体类型是什么,源码如下。Node是HashMap的内部类,实现了Map.Entery接口,主要就是存放我们put方法所添加的元素。其中的next就表示这可以构成一个单向链表,这主要是通过链地址法解决发生hash冲突问题。而当桶中的元素个数超过阈值的时候就换转为红黑树。
上面只是大概了解了一下HashMap的简单组成,下面主要介绍其中的一些参数和重要的方法原理实现。
该方法的作用就是:返回大于initialCapacity的最小的二次幂数值。如下实例
我们看看HashMap源码中为我们提供的四个构造方法。我们可以看到,平常我们最常用的无参构造器内部只是仅仅初始化了loadFactor,别的都没有做,底层的数据结构则是延迟到插入键值对时再进行初始化,或者说在resize中会做。后面说到扩容方法的实现的时候会讲到。
不管增加、删除、查找键值对,定位到哈希桶数组的索引都是很关键的第一步,所以我们看看源码怎样通过hash()方法以及其他代码确定一个元素在hash桶中的位置的。
下面我们通过一个例子计算一下上面这个定位的过程,假设现在桶大小n为16.
我们可以看到,这里的hash方法并不是用原有对象的hashcode最为最终的hash值,而是做了一定位运算,大概因为如果(n-1)的值太小的线) & hash的值就完全依靠hash的低位值,比如n-1为0000 1111,那么最终的值就完全依赖于hash值的低4位了,这样的话hash的高位就玩完全失去了作用,h ^ (h 16),通过这种方式,让高位数据与低位数据进行异或,也是变相的加大了hash的随机性,这样就不单纯的依赖对象的hashcode方法了。
可以看到主要逻辑在put方法中调用了putVal方法,传递的参数是调用了hash()方法计算key的hash值,主要逻辑在putVal中。可以结合注释熟悉这个方法的执行,我在这里大概总结一下这个方法的执行:
2.定位元素在桶中的位置,具体就是通过key的hash值和hash桶的长度计算得到下标i,如果计算到的位置处没有元素(null),那么就新建结点然后添加到该位置。
3.如果table[i]处不为null,已经有元素了,那么就表明产生hash冲突,这里可能是三种情况
②如果不是因为key一样,那么需要判断当前该桶是不是已经转为了红黑树,是的话就构造一个TreeNode结点插入红黑树;
③不是红黑树,就使用链地址法处理冲突问题。这里主要就是遍历链表,如果在遍历过程中也找到了key一样的元素,那么久还是使用新值替换旧值。否则会遍历到链表结尾处,到这里就直接新添加一个Node结点插入链表,插入之后还需要判断是不是已将超过了转换为红黑树的阈值8,如果超过就会转为红黑树。
5.判断插入后的size大小是不是超过了threshhold,如果超过需要进行扩容。
我这里添加上一点,就是为什么使用 (e.hash & oldCap) == 0判断是处于原位置还是放在更新的位置(原位置+旧容量),解释如下:我们知道capacity是2的幂,所以oldCap为10...0的二进制形式(比如16=10000B)。
(1)若判断条件为真,意味着oldCap为1的那位对应的hash位为0(1&0=0,其他位都是0,结果自然是0),对新索引的计算没有影响,至于为啥没影响下面就说到了。先举个例子计算一下数组中的下标在扩容前后的变化:
从上面计算发现,当cap为1的那位对应的hash为0的时候,resize前后的index是不变的。我们再看下面,使用上面的hash值,对应的就是 (e.hash & oldCap) == 0,恰好也是下标不变的
从上面计算发现,当cap为1的那位对应的hash为1的时候,resize前后的index是改变的。我们再看下面,使用上面的hash值,对应的就是 (e.hash & oldCap) != 0,恰好下标就是原索引+原容量
这一部分其实和put方法中,使用链地址法解决hash冲突的原理差不多,都是对链表的操作。
判断当前oldTab长度是否为空,如果为空,则进行初始化桶数组,也就回答了无参构造函数初始化为什么没有对容量和阈值进行赋值,如果不为空,则进行位运算,左移一位,2倍运算扩容。扩容,创建一个新容量的数组,遍历旧的数组:如果节点为空,直接赋值插入如果节点为红黑树,则需要进行进行拆分操作(个人对红黑树还没有理解,所以先不说明)如果为链表,根据hash算法进行重新计算下标,将链表进行拆分分组(相信看到这里基本上也知道链表拆分的大致过程了)
基本逻辑就是根据key算出hash值定位到哈希桶的索引,当可以就是当前索引的值则直接返回其对于的value,反之用key去遍历equal该索引下的key,直到找到位置。
以上就是深入理解Java中的HashMap的详细内容,更多关于Java HashMap的资料请关注脚本之家其它相关文章!