我们都知道,Hashmap是设定框架下地图的实现类,而不是线程安全。Hashmap继承了AbstractMap类并实现了映射,可隔离,可序列化接口。以下是源代码:
从上图,我们可以看到,哈希图的基础数据结构由链接列表(1.7及以前)组成。在JDK1.8之后,它由一系列链接列表加红色和黑树组成,因为当链接列表的长度超过8时,HashMap将尝试将链接列表转换为红树和黑树,只是为了便于搜索到搜索到搜索避免从过度链接的列表中避免链接列表,这些列表会导致我们的查询效率降低。(红树和黑树是自我平衡的二进制树,不清楚的朋友可以自己学习)。
关于节点阵列表:如上图所示,我们的hashmap在底部保持节点阵列。当hashmap中的put元素首先是第一次时,表将其初始化。
如果在初始化hashmap时未指定无法指定容量,则在初始化表(即16)时,使用默认default_initial_capacity参数,即表初始化的长度。
如果在初始化hashmap时指定了容量,则哈希姆普将将此容量修改为2的功率时间,然后创建一个具有相应长度的表格。当表扩展时的双时间。
/**
*表,首次使用初始化,并根据需要调整大小。在分布中,长度始终是2的功率(我们仍然可以在某些操作中容忍,以允许公差的长度允许当前不需要的指导机制。)
**/
瞬态节点
默认情况下,哈希图的容量为16。
当Hashmap执行PUT操作时,将通过以下步骤:
首先,我们可以看到putval()方法被调用,我们的密钥的哈希值传递给
让我们看看这个哈希(键)方法中的内容
在这里,我们可以看到计算键的哈希码,并在左侧的哈希码后向左移动。最后,我们在hashmap中获得了hashmap值。这是什么目的?主要是要使Key的哈希码高度参与操作,从而降低了哈希碰撞的可能性。
我们可以看到,当表阵列为空时,调用了resize()方法,因此我们可以知道,当我们刚出来时,该表实际上是空的。只有将其分配给此hashmap时,它才会将表初始化为16的数组。让我们看一下resize()方法源代码:
要了解此源代码,首先,我们需要知道一些变量的含义:
在第一个put值之前,由于表为null,因此目前将执行以下代码以将原始值授予表。如果我们不指定新的hashmap时的容量,则将初始化为16至16。
然后,我们不会首先查看其他代码,请返回putval()方法继续查看,以下判断中有一个代码
从上面,我们可以知道n是表阵列的长度。这是在计算之前和计算之前计算的哈希值的N-1。这是什么目的?因为时间是耗时的,并且此操作经常在hashmap(值,put,扩展等)中使用,因此可以消耗一定量的性能,并且位计算速度比剩余操作更快。
然后,我们看到这里构建了一个新节点,该节点已分配给标签[i]。实际上,这是该表上没有数据的操作。当值得的计算值得,执行以下操作:
1.确定表[i]的哈希值是否等同于put值和关键值。与此相比,这是相比的。
如果您平等,请给出p(e实际上是我们需要在地图中修改的节点节点,并在末尾替换原始节点);最后,原始节点);
2.如果P是及时的节点,这意味着它是红色和黑色的树,请调用Puttreeval(),这是Putval的树版本。您在这里没有详细解释。您可以自己阅读源代码。
3.在其他情况下:穿越节点链接列表,如果您遇到与插入节点相同的键值,则直接基于;如果没有相同的话,请将其放在链接列表的末尾,然后您需要判断链接列表的长度是否大于8.);方法,尝试将节点链接列表转换为红色和黑树。为什么要尝试?让我们看一下源代码:
min_treeify_capacity:您可以使用垃圾箱的最小表面容量;如您所见,如果表的长度不超过Min_tree_capacity,则为64,resile(ps:ps:又是rase方法...和黑树(稍后的判断是确定桌子不是要为空的)。LET看一下调整大小的方法
然后,我们以前跳过了一些代码。首先,让我们看一下此代码:
OldCap是数字长度。如果数组的数量超过29位29的最大_capacity,则将阈值分配给integer.max_value。这很明显,当我们使用它时,这是不可能发生的。因此,我们不需要阅读本段,然后是下一个判断,如果oldcap*2小于2x10的29,大于16,那么容量的双重然后,我们查看以下代码:
以上代码是重新扩展原始表中所有节点节点的扩展。具体计算如下:
在正常情况下,表中计算节点的方法为:hash&(oldtable.length-1),在膨胀之后,表双重的长度。计算表投标的方法是哈希&(newtable.length-),即哈希&(oldtable.length*2-1),因此我们有这样一个结论:两个新的和旧计算的结果,否则,否则,新的出价等于旧投标的长度以及旧数组。
假设表的原始长度为16和32,则在计算容量之前和之后表的表计算表的表计算:
哈希值的每个二进制位置由ABCDE表示。然后,最后4位显然与哈希和旧表的结果相同。b为0是0,而新表格与旧表的结果相同。相反,如果B所在的位置为1,则新表被位置的位置和结果压制,位置的结果以及位置的结果以及位置的结果以及该位置的结果以及结果位置和位置的结果以及位置的结果以及位置的结果以及位置的结果以及位置的结果以及位置的结果以及位置的结果以及该位置的结果以及位置和位置的结果以及位置的结果以及位置的结果以及位置的结果以及位置的结果,位置的结果和位置的结果比旧桌子多100,000(二进制),这是二进制10,000是旧表16的长度。因此,在扩展扩展之后,原始节点将基于哈希值的第五位为0或1,以获得新的表格竞标(要么原始设置为不变,或原始投标值+原始投标值+原始出价值+原始表的长度,因此长期链接的列表分散到两个链接列表中,因此链接列表的长度将较短,这就是为什么红色和红色和黑树再次散布。
然后,我们继续返回主要方法(putval):
这是对E是否为空的判断。通过以前的代码,我们可以知道,当我们具有重复的节点时,E不是空的,否则我们将其放在链接列表的末尾,同时为null分配e value。注意这里:
Onlyifabsent:如果是真的,它将不会更改现有值
以前传递了参数的数量,默认值为false。不清楚的朋友可以回去查看最外层的put方法中的putval()句子。在这一点上,我们的put方法完成了。
慢慢喝水..
实际上,在获取方法中没有什么可说的,只需拿起哈希,找到一个位置,返回值很好,代码如下:
在这里,您可以像PUT方法一样调用Hash(键),也不要说它,然后是getNode()方法。让我们单击以查看:
该过程如下:根据哈希值,计算表格中的出价,找到第一个节点,并判断它是否直接在饭后,否则将判断是否有较低的节点,然后判断是否是树节点或链接列表。根据情况,根据情况,情况选择了不同的方法来促进搜索,从第一个搜索往下看,然后在发现后返回。如果最终找不到,请返回null。在这一点上,GET方法结束了。
容量何时扩大?
实际上,扩展是通过调整大小方法实施的。有两种扩展情况。一个是,当put节点时,表阵列的长度超过了阈值,即表的长度。在64时,链接列表的长度将通过扩展容量来减少。
为什么要计算哈希值以移动键的hashcode右16位,然后与其进行操作?
因为关键值的主题码为32位,并且我们数组的最大长度为integer.maxvalue,为16位,因此计算中的实际参与最多为16位数字数据。对于键值的HSAHCODE高度,要减少哈希碰撞的概率也是16位。
为什么桌子的长度必须是2的力量?
首先,我们需要了解数学知识:如果n是2的功率时间,则(n -1)和哈希等同于n%哈希。此操作经常用于hashmap(值,put,扩展等),因此具有一定的性能,并且位计算速度比剩余操作更快。剩余操作。