我知道从 Java 8 开始,如果 HashMap 有足够多的哈希冲突,并且键实现了 Comparable,它会 use a balanced tree instead of a linked list for the bin .但据我所知,Comparable 接口(interface) does not require compareTo() 应“与 equals() 一致”(尽管强烈建议这样做)。
我错过了什么吗?似乎新的实现允许 HashMap 违反 Map 接口(interface)的要求,如果键恰好具有兼容但不推荐的 Comparable 实现。
以下 JUnit 测试在 OpenJDK 8u72 上暴露了此行为:
import static org.junit.Assert.*;
import java.util.HashSet;
import java.util.Set;
import org.junit.Test;
class Foo
implements Comparable<Foo> // Comment this out to fix the test case
{
private final int bar;
private final int baz;
Foo(int bar, int baz) {
this.bar = bar;
this.baz = baz;
}
public boolean equals(Object obj) {
// Note that this ignores 'baz'
return obj instanceof Foo && bar == ((Foo) obj).bar;
}
public int hashCode() {
return 0;
}
public int compareTo(Foo o) {
// Inconsistent with equals(), but seems to obey the requirements of
// Comparable<Foo>
return Integer.compare(baz, o.baz);
}
}
public class FooTest {
@Test
public void test() {
Set<Foo> set = new HashSet<>();
for (int i = 0; i < 128; ++i) {
set.add(new Foo(i, 0));
}
// This fails if Foo implements Comparable<Foo>
assertTrue(set.contains(new Foo(64, 1)));
}
}
最佳答案
这不是 IMO 任何地方的错误,因为代码的行为符合实现者的预期 - 但这是不寻常的 Comparable 实现的已知结果。来自Comparable documentation :
It is strongly recommended (though not required) that natural orderings be consistent with
equals. This is so because sorted sets (and sorted maps) without explicit comparators behave "strangely" when they are used with elements (or keys) whose natural ordering is inconsistent withequals. In particular, such a sorted set (or sorted map) violates the general contract for set (or map), which is defined in terms of theequalsmethod.
虽然这不是正常意义上的有序集或映射,但与这个问题有明确的关系。
我同意这是一个可能的问题,而且是一个真正微妙的问题,特别是因为它很难在简单的情况下重现。我会更新您的文档以引起非常强烈的注意,您的类以与 equals 不一致的方式实现 Comparable,并特别将其称为潜在问题.
关于java - Java 8's HashMap misbehaves if the keys implement Comparable in a way that isn' t 与equals一致是不是bug?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35164645/