【发布时间】:2017-07-27 13:55:29
【问题描述】:
我很难理解 java-9 ImmutableCollections.SetN 的实现细节;具体为什么需要将内部数组增加两次。
假设你这样做:
Set.of(1,2,3,4) // 4 elements, but internal array is 8
更确切地说,我完全理解为什么在 HashMap 的情况下这样做(双重扩展) - 你永远(几乎)不希望 load_factor 成为一个。例如,!=1 的值会缩短搜索时间,因为条目可以更好地分散到存储桶中。
但如果是 不可变集 - 我真的说不出来。特别是因为选择了内部数组的索引方式。
让我提供一些细节。首先是如何搜索索引:
int idx = Math.floorMod(pe.hashCode() ^ SALT, elements.length);
pe 是我们放入集合中的实际值。 SALT 仅在启动时生成 32 位,每个 JVM 一次(如果您愿意,这是实际的随机化)。 elements.length 对于我们的示例是 8(4 个元素,但这里是 8 个 - 大小翻倍)。
这个表达式就像一个负安全模运算。请注意,在选择桶时,在HashMap中在HashMap中完成相同的逻辑事物。
所以如果我们的例子是elements.length is 8,那么这个表达式将返回任何小于8的正值(0, 1, 2, 3, 4, 5, 6, 7)。
现在剩下的方法:
while (true) {
E ee = elements[idx];
if (ee == null) {
return -idx - 1;
} else if (pe.equals(ee)) {
return idx;
} else if (++idx == elements.length) {
idx = 0;
}
}
让我们分解一下:
if (ee == null) {
return -idx - 1;
这很好,这意味着数组中的当前槽是空的——我们可以把我们的值放在那里。
} else if (pe.equals(ee)) {
return idx;
这很糟糕 - 插槽已被占用,并且已经到位的条目等于我们想要放置的条目。 Sets 不能有重复的元素 - 所以稍后会抛出异常。
else if (++idx == elements.length) {
idx = 0;
}
这意味着这个槽被占用了(哈希冲突),但是元素不相等。在HashMap 中,此条目将被放入与LinkedNode 或TreeNode 相同的存储桶中——但此处并非如此。
所以index 递增并尝试下一个位置(有一点需要注意的是,当它到达最后一个位置时它会以圆形方式移动)。
问题是:如果在搜索索引时没有做任何花哨的事情(除非我遗漏了什么),那么为什么需要一个两倍大的数组呢?或者为什么函数不是这样写的:
int idx = Math.floorMod(pe.hashCode() ^ SALT, input.length);
// notice the diff elements.length (8) and not input.length (4)
【问题讨论】:
-
@GhostCat github.com/netroby/jdk9-dev/blob/master/jdk/src/java.base/share/…(
probe方法) -
@VinceEmigh 结束其他讨论:事情往往不是非黑即白。我已经看到很多 6digits 人的答案,它们确实提供了更少的内容或更多的“模糊性”,但在几个小时内获得了大量选票。而且我已经看到好内容长期存在......并且没有任何事情发生。你看 - 零个其他答案,甚至没有这个问题的 cmets。因此,可能的解释列表可能不能解释一个很好的答案——但它可以提供思考的食物。除此之外:这不就是投票的目的吗?我将反对票作为直接反馈......好吧:我尝试这样做
-
@VinceEmigh 下次想出更好的东西。
标签: java collections java-9