作者:william浩浩_597 | 来源:互联网 | 2023-01-27 15:45
正如标题所示,这是一个关于实现细节的问题HashMap#resize
- 当内部数组的大小加倍时.这有点罗嗦,但我真的试图证明我对此有了最好的理解......
这发生在这个特定桶/箱中的条目以某种方式存储的时刻Linked
- 因此具有确切的顺序并且在问题的上下文中这是重要的.
一般来说,resize
也可以从其他地方调用,但我们只看这个案例.
假设你将这些字符串作为键放在一个HashMap
(右边是hashcode
后面 HashMap#hash
- 那是内部重新散列.)是的,这些都是精心生成的,而不是随机的.
DFHXR - 11111
YSXFJ - 01111
TUDDY - 11111
AXVUH - 01111
RUTWZ - 11111
DEDUC - 01111
WFCVW - 11111
ZETCU - 01111
GCVUR - 11111
这里有一个简单的模式 - 最后4位对于所有这些都是相同的 - 这意味着当我们插入这些键中的8个(总共9个)时,它们最终会在同一个桶中; 并在9个HashMap#put
时,resize
将被调用.
因此,如果当前有8个条目(上面有一个键)HashMap
- 这意味着在这个映射中有16个桶,它们的最后4个位决定了条目最终的位置.
我们把第九个键.此时TREEIFY_THRESHOLD
被击中并被resize
召唤.这些容器加倍,32
并且键的另一位决定了该条目的位置(因此,现在为5位).
最终到达这段代码(当resize
发生时):
Node loHead = null, loTail = null;
Node hiHead = null, hiTail = null;
Node next;
do {
next = e.next;
if ((e.hash & oldCap) == 0) {
if (loTail == null)
loHead = e;
else
loTail.next = e;
loTail = e;
}
else {
if (hiTail == null)
hiHead = e;
else
hiTail.next = e;
hiTail = e;
}
} while ((e = next) != null);
if (loTail != null) {
loTail.next = null;
newTab[j] = loHead;
}
if (hiTail != null) {
hiTail.next = null;
newTab[j + oldCap] = hiHead;
}
它实际上并不复杂......它的作用是将当前的bin分成多个条目,这些条目将移动到其他bin和不会移动到其他bin的条目- 但是肯定会保留在这个bin中.
它实际上是非常聪明的 - 它是通过这段代码:
if ((e.hash & oldCap) == 0)
这样做是检查下一位(在我们的例子中是第5位)是否实际为零 - 如果是,则表示该条目将保持原样; 如果不是,它将以新箱中的两个偏移力移动.
最后问题是:调整大小中的那段代码是经过仔细制作的,以便保留该 bin中条目的顺序.
所以在你将这9个键放入HashMap
顺序之后将是:
DFHXR -> TUDDY -> RUTWZ -> WFCVW -> GCVUR (one bin)
YSXFJ -> AXVUH -> DEDUC -> ZETCU (another bin)
你为什么要保留一些条目的顺序HashMap
?在订单Map
是真的详见坏在这里或在这里.