Java 8';当许多键具有相同的哈希代码时,s哈希映射退化为平衡树?

Java 8';当许多键具有相同的哈希代码时,s哈希映射退化为平衡树?,java,hashmap,java-8,Java,Hashmap,Java 8,当许多键具有相同的哈希代码时,Java8的哈希映射如何退化为平衡树?我读到,键应该实现compariable来定义排序。HashMap如何结合哈希和自然排序来实现树?如果类没有实现可比,或者当多个互不可比的可比实现是同一映射中的键时,该类会怎么样?HashMap有自己的哈希方法,该方法对内部对象应用补充的2位长度哈希,以避免此问题: 对给定的哈希代码应用补充哈希函数,以防止低质量的哈希函数。这是至关重要的,因为HashMap使用两个长度哈希表的幂,否则会遇到低位不不同的哈希代码冲突。注意:空键总

当许多键具有相同的哈希代码时,Java8的哈希映射如何退化为平衡树?我读到,键应该实现
compariable
来定义排序。HashMap如何结合哈希和自然排序来实现树?如果类没有实现
可比
,或者当多个互不可比的
可比
实现是同一映射中的键时,该类会怎么样?

HashMap
有自己的哈希方法,该方法对内部对象应用补充的2位长度哈希,以避免此问题:

对给定的哈希代码应用补充哈希函数,以防止低质量的哈希函数。这是至关重要的,因为HashMap使用两个长度哈希表的幂,否则会遇到低位不不同的哈希代码冲突。注意:空键总是映射到散列0,因此索引为0

如果你想看看它是怎么做的,看看里面的

读这本书。这主要是一个问题

它实际上不需要实现
compariable
,但如果可用,可以使用它(例如,请参见)

在HashMap中,对HashMap操作的描述要比我自己编写的更好。理解树节点及其顺序的相关部分包括:

此映射通常充当一个装箱(带扣)的哈希表,但当箱子太大时,它们会转换为树节点的箱子,每个箱子的结构与java.util.TreeMap中的类似。[…]树节点的容器可以像其他任何容器一样被遍历和使用,但在人口过多时,还支持更快的查找。[……]

树型箱(即,其元素均为树节点的箱)主要通过hashCode进行排序,但在关系的情况下,如果两个元素属于相同的“class C implements Compariable”类型,则使用它们的compareTo方法进行排序。(我们通过反射保守地检查泛型类型以验证这一点——请参见方法)。在提供最坏情况下的O(log n)操作时,当键具有不同的散列或可排序时,树容器的额外复杂性是值得的,因此,在偶然或恶意使用情况下,性能会下降,其中hashCode()方法返回的值分布不均,以及许多键共享一个散列代码,只要它们是可比的。(如果两者都不适用,与不采取预防措施相比,我们可能会浪费大约两倍的时间和空间。但唯一已知的情况是由于糟糕的用户编程实践导致的,这些实践已经非常缓慢,几乎没有什么区别。)

当两个对象的散列码相等但不可相互比较时,将调用方法打破这种关系,首先通过对
getClass().getName()
(!)进行字符串比较,然后通过比较
System.identityHashCode


假设哈希表至少有容量(当前为64),则实际的树构建从中开始,从bin到达(当前为8)时开始。这是一个基本正常的红黑树实现(),以与散列箱(例如)相同的方式支持遍历有一些复杂性。

事实上,不是。
散列
函数减少但不消除冲突,因此,
HashMap
仍然必须管理具有相同哈希值的密钥。您已链接到旧版本的源代码。查看Java8代码,您将看到它不再进行补充的重新灰化。该方法已不存在。但若hashcode()未在对象中被重写,则它仍将调用System.identityHashCode()来查找hashbucket。那个么,若key不覆盖hashcode()并调用了tiebarkerder,那个么会发生什么呢?或者它是否会被调用?@RohitSachan如果密钥类型使用默认的标识语义,则任何存储桶都不太可能满到足以转换为树存储桶,因为标识哈希代码分布良好。但是这种情况没有特殊的处理,所以是的,
tiebarkorder
仍然会调用
identityHashCode
来进行排序。@Rohit Sachan:如果每次优化尝试都失败,它必须求助于Java 8之前版本中已知的相同的链表行为。@NateGlenn在不可比较的情况下似乎是两全其美的(最后一个else if and else),但我需要一步一步地调试。这就提出了一个问题,为什么在这种情况下,命令是必需的。@NateGlenn推测:字符串是最常见的JDK控制类型。在特殊情况下,每次额外的类检查带来的好处较少,而在一般情况下会增加成本,也许字符串就是必需的最佳折衷。请注意,字符串是最终的,因此它不是用于子类防御。它可能是为了防止基于哈希冲突的DoS攻击;字符串哈希代码并不总是最好的。在某个点上,有一个很大的字符串列表哈希到最小值,包括“PolyGene”.我想其他值的碰撞也是可能的。
static int hash(int h) {
    // This function ensures that hashCodes that differ only by
    // constant multiples at each bit position have a bounded
    // number of collisions (approximately 8 at default load factor).
    h ^= (h >>> 20) ^ (h >>> 12);
    return h ^ (h >>> 7) ^ (h >>> 4);
}