谁能简单地解释一下,为什么这段代码抛出一个异常,“比较方法违反了它的一般契约!”,以及我该如何修复它?

private int compareParents(Foo s1, Foo s2) {
    if (s1.getParent() == s2) return -1;
    if (s2.getParent() == s1) return 1;
    return 0;
}

当前回答

你不能像这样比较对象数据:s1.getParent() == s2 -这将比较对象引用。你应该重写Foo类的equals函数然后像这样比较它们s1.getParent()。equals(s2)

其他回答

只是因为这是我得到的当我谷歌这个错误,我的问题是我有

if (value < other.value)
  return -1;
else if (value >= other.value)
  return 1;
else
  return 0;

>= other。Value(显然)实际上应该是Value > other。值,这样你就可以用相等的对象返回0。

你不能像这样比较对象数据:s1.getParent() == s2 -这将比较对象引用。你应该重写Foo类的equals函数然后像这样比较它们s1.getParent()。equals(s2)

违反合同通常是指比较者在比较对象时没有提供正确或一致的值。例如,你可能想要执行一个字符串比较,并强制空字符串排序到最后:

if ( one.length() == 0 ) {
    return 1;                   // empty string sorts last
}
if ( two.length() == 0 ) {
    return -1;                  // empty string sorts last                  
}
return one.compareToIgnoreCase( two );

但是这忽略了1和2都为空的情况——在这种情况下,返回了错误的值(1而不是0以显示匹配),比较器将其报告为违规。它应该写成:

if ( one.length() == 0 ) {
    if ( two.length() == 0 ) {
        return 0;               // BOth empty - so indicate
    }
    return 1;                   // empty string sorts last
}
if ( two.length() == 0 ) {
    return -1;                  // empty string sorts last                  
}
return one.compareToIgnoreCase( two );

编辑虚拟机配置对我很有用。

-Djava.util.Arrays.useLegacyMergeSort=true

你的比较器是不可传递的。

假设A是B的父类,B是C的父类,因为A > B和B > C,那么A > C必须是这样。然而,如果你的比较器在A和C上被调用,它将返回零,这意味着A == C。这违反了契约,因此抛出异常。

库能够检测到这一点并让您知道,而不是表现得不稳定,这是相当不错的。

在compareParents()中满足传递性要求的一种方法是遍历getParent()链,而不是只查看直接祖先。