这是代码的一部分。 当节点长度超过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()有关。
答案 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]
。