Java 为什么HashMap对不可比较的键使用TreeNode?
我知道,在Java8中,HashMap针对分布不均匀的hashCode进行了优化。当超过阈值时,它会将bucket中的节点从链表重建到树中。另外,这种优化对于不可比较的密钥不起作用,至少性能没有提高。在下面的示例中,我将不可比较的键放入HashMap 但是检查堆转储显示节点被重新排列到树中Java 为什么HashMap对不可比较的键使用TreeNode?,java,java-8,hashmap,Java,Java 8,Hashmap,我知道,在Java8中,HashMap针对分布不均匀的hashCode进行了优化。当超过阈值时,它会将bucket中的节点从链表重建到树中。另外,这种优化对于不可比较的密钥不起作用,至少性能没有提高。在下面的示例中,我将不可比较的键放入HashMap 但是检查堆转储显示节点被重新排列到树中 我的问题是,如果不能提高性能,为什么要将节点重建到树中?在这种情况下,根据哪些标准比较节点,以确定哪个键应该是右节点,哪个键应该是左节点?我认为您误解了答案的意思。不需要Compariable,它只是一种优化
我的问题是,如果不能提高性能,为什么要将节点重建到树中?在这种情况下,根据哪些标准比较节点,以确定哪个键应该是右节点,哪个键应该是左节点?我认为您误解了答案的意思。不需要Compariable,它只是一种优化,可以在散列相等时使用,以决定将条目移动到左侧或右侧完全平衡的红黑树节点。稍后,如果键不可比较,它将使用System.identityHashcode 找出哪个键应该是右节点,哪个键应该是左节点
它向右移动-较大的键向右移动,但是树可能需要平衡。通常,您可以查找一棵树如何成为完全平衡的红黑树的确切算法,如Afaik它不使用标识哈希代码,只使用key对象的哈希代码。@jornverne它使用。请参阅内部的TieborkOrder方法HashMap@Eugene这是散列码相等时的回退,这不一定是散列冲突的情况,尽管我猜在本例中是这样。如果你看一下它在putTreeVal中的使用位置,你会看到它在这之前尝试使用密钥的哈希代码。很抱歉,我误解了你的意思@尤金是对的。我忘了订领带了。它首先通过自己的散列计算目录,然后使用可比较的,最后使用System.identityHashCode,这是一个全局唯一的散列代码。@ArtemPetrov这是一个很好的观点!以下是对此的解释:
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;
}
}