我知道在Java 8 HashMap
中针对分布不佳的hashCode
进行了优化。在超过阈值的情况下,它会将存储桶中的节点从链接列表重建为树。另外,stated这种优化对于不具有可比性的密钥并不起作用(在性能方面没有得到改善)。在下面的示例中,我没有将Comparable
个密钥放入HashMap
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;
class Main {
public static void main(String[] args) throws InterruptedException {
Map<Key, Integer> map = new HashMap<>();
IntStream.range(0, 15)
.forEach(i -> map.put(new Key(i), i));
// hangs the application to take a Heap Dump
TimeUnit.DAYS.sleep(1);
}
}
final class Key {
private final int i;
public Key(int i) {
this.i = i;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Key key = (Key) o;
return i == key.i;
}
@Override
public int hashCode() {
return 1;
}
}
但是检查堆转储显示节点重新排列成树。
我的问题是,为什么节点会重建到树中,如果它不会提高性能,在这种情况下比较节点的哪个标准,以确定哪个键应该是正确的节点,哪个键离开?
答案 0 :(得分:5)
我认为你有点误解了答案所说的。 Comparable
不是需要,它只是在哈希相等时可能会使用的优化 - 以便决定将条目移动到哪里 - 向左或向右(perfectly balanced red-black tree node
)。如果密钥不可比较,则会使用System.identityHashcode
。
找出哪个键应该是正确的节点,哪个键留下
它向右移动 - 更大的键向右移动,但树可能需要平衡。 通常您可以查找Tree
成为perfectly balanced red black tree
的确切算法,例如here