我从JDK1.8的HashMap遇到一些麻烦

时间:2018-12-19 08:41:47

标签: java hashmap resize

这是代码的一部分。 当节点长度超过7时,它将把Node变为TreeNode,但是在函数treeifyBin()中,如果制表符长度小于64,则只需执行resize()。

// binCount is length of Node,  TREEIFY_THRESHOLD is default 8
if (binCount >= TREEIFY_THRESHOLD - 1)
    treeifyBin(tab, hash);

// tab is Node[],  MIN_TREEIFY_CAPACITY is default 64
if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
    resize();

我不明白为什么节点长度与resize()有关。

2 个答案:

答案 0 :(得分:2)

您知道,随着java-8哈希图的内部工作变化,当内部链接列表达到阈值时,它将转换为树(具体来说是RB树)。转换树的逻辑取决于存储桶中节点的长度,因此其价值在将列表转换为树之前进行检查,是否仅通过调整链表的大小即可插入节点,而不是将列表转换为树,这是一项昂贵的操作。这里需要考虑的另一件事是,频繁从地图中删除会导致树再次转换回列表,因此在treeifybin()方法内部,需要检查调整大小,然后将当前结构更改为树。

有关更多信息,请检查以下内容: http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/classes/java/util/HashMap.java

干杯:)

答案 1 :(得分:0)

创建HashMap的核心目标是,您想在固定时间O(1)中检索一个值。但是,发生碰撞时,它不会保留为O(1)。如果发生冲突,则必须在链接列表或树中搜索键。

在这里,您位于函数treeifyBin()中。这意味着您已经遇到了碰撞。但是我们讨厌碰撞。我们一定要避免碰撞。但是创建树是很多工作。因此,在创建树之前,我们检查数组(或选项卡)是否仍然足够小(< MIN_TREEIFY_CAPACITY)。如果是这样,我们将增加数组的大小以避免冲突,而不是创建树。

现在,让我们看看增加数组大小如何避免冲突。假设初始数组大小为16。现在要将哈希码映射到数组索引,您执行按位与(hashCode & (sizeOfArray - 1))。这里,(16-1)的二进制为1111。如果哈希码为17(二进制= 10001),则按位与后得到的全部为0001,即1。现在,如果调整大小,则数组大小将为32。因此,{{1 }}。现在,如果使用相同的哈希码17进行按位与运算,将得到(sizeOfArray - 1) = 11111,即17。因此,该元素将从10001移到tab [1]。如果另一个较早发生冲突的键的哈希码更早为1或33,则它仍将进入tab[17]