私はJava 8以降、HashMap
に十分なハッシュ・コリジョンがあり、キーにComparable
が実装されていれば、それはuse a balanced tree instead of a linked list for the binになります。しかし、私が見ることができるから、のインターフェイスdoes not requireはと一致しています。(これは強くお勧めしますが)compareTo()
です。キーがequalsと矛盾する方法でComparableを実装している場合、Java 8のHashMapが誤動作するバグですか?
私は何かを見逃しましたか?キーが準拠しているが、推奨されていないComparable
の実装を持つ場合、新しい実装でHashMap
がMap
インターフェイスの要件に違反するように思われます。
次の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)));
}
}
新しい実装の既知の期待された動作であるという点ではバグではないと思われます... 'TreeMap'は常に' equals'ではなくorder比較を使用しているので、同じ問題があります。 –
@JonSkeet真実ですが、そのため私は 'HashMap'を使っています:)。具体的には、キーが推奨されない 'Comparable'実装を持っていることを知っていたので、意図的にJava 7で' HashMap'( 'TreeMap'ではなく)を使用していたコードについて心配しています。 Java 8にアップグレードすると、非常に微妙なバグが発生する可能性があります。 –
[java.math.BigDecimal](https://docs.oracle.com/javase/8/docs/api/java/math/BigDecimal.html#compareTo-java.math.BigDecimal-)クラスは、次の例です。 JDKに含まれているequalsと矛盾します。 – jmehrens