Comparator 的 JavaDoc 指出
It is strongly recommended (though not required) that natural orderings be consistent with equals.
他们还给出了 (a.equals(b) && c.compare(a,b) != 0)
时的“奇怪”行为示例。
现在,有人可以给我一个在 (!a.equals(b) && c.compare(a,b) == 0)
情况下“奇怪”行为的例子吗?第二种情况应该比第一种情况更常见,因为在实现 Comparator
时很容易忘记为比较类型实现 equals
。如果不知道 TreeSet
的实现,就很难想出一个例子。
(这是一个更长的故事,为什么这个问题与我相关。而且这不是一项家庭作业)
最佳答案
这是一个简单的演示。我们有一个名为 Strange
的类,它使用不区分大小写的字符串比较来实现 equals
和 hashCode
,但实现了 compareTo
区分大小写。
class Strange implements Comparable<Strange> {
final String s;
public Strange(String s) {
this.s = s;
}
@Override
public boolean equals(Object o) {
// Kind of equals - case insensitive.
return (o instanceof Strange) && ((Strange) o).s.equalsIgnoreCase(s);
}
@Override
public int hashCode() {
// Consistent with equals.
return s.toUpperCase().hashCode();
}
@Override
public int compareTo(Strange o) {
// Exact ordering including case - inconsistent with equals.
return s.compareTo(o.s);
}
@Override
public String toString() {
return s;
}
}
public void test() {
Set<Strange> set1 = new HashSet<>();
Set<Strange> set2 = new TreeSet<>();
for (String s : new String[]{"Hello", "hello", "Everyone", "everyone"}) {
Strange strange = new Strange(s);
set1.add(strange);
set2.add(strange);
}
System.out.println("Set1: " + set1);
System.out.println("Set2: " + set2);
}
我们得到 - 正如您可能期望的那样:
Set1: [Hello, Everyone]
Set2: [Everyone, Hello, everyone, hello]
看看将字符串放入 TreeSet
中会如何改变结果?这是因为 TreeSet
使用 compareTo
,而 HashSet
使用 equals
和 hashCode
。这可能会以多种不同(最重要的意外)方式破坏事物,因为您不必知道在幕后使用哪种Set
。
这表明 (a.equals(b) && a.compareTo(b) != 0)
给出了奇怪的结果。很容易证明相反的问题 (!a.equals(b) && a.compareTo(b) == 0)
也表现出奇怪的结果。
关于java - 比较器和违反集合的约定,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28713998/