Java7 - 比较方法违反了它的一般契约(TimSort.java)
Java7 - Comparison method violates its general contract (TimSort.java)
这是我得到的堆栈跟踪
Caused by: java.lang.IllegalArgumentException: Comparison method violates its general contract!
at java.util.TimSort.mergeLo(TimSort.java:777)
at java.util.TimSort.mergeAt(TimSort.java:514)
at java.util.TimSort.mergeCollapse(TimSort.java:441)
at java.util.TimSort.sort(TimSort.java:245)
at java.util.Arrays.sort(Arrays.java:1512)
at java.util.ArrayList.sort(ArrayList.java:1454)
at java.util.Collections.sort(Collections.java:175)
at xxx.sortDisplayFields(OfferFieldLayout.java:521)
这里是比较方法:
public int compare(Field pObject1, Field pObject2)
{
int compare = 0;
//...
if (compare == 0)
{
if (pObject1.hashCode() <= pObject2.hashCode())
{
compare = -1;
}
else
{
compare = 1;
}
}
return compare;
}
我认为这是由于传递性 属性 没有得到尊重:
传递性:如果 A > B 且 B > C,则对于任何 A、B 和 C:A > C。
我试图想出一个反例,但我在这里失败了,感谢任何帮助!
你的函数永远不会return0!这意味着如果对象中的所有内容都相等,包括哈希码,那么 pObject1.compare(pObject2)
将不等于 pObject2.compare(pObject1)
。比较函数必须是对称的。我还认为你在那次测试中交换了 -1
和 1
,所以你最后一次检查应该是这样的:
if (compare == 0) {
if (pObject1.hashCode() < pObject2.hashCode()) {
compare = 1;
} else if (pObject1.hashCode() > pObject2.hashCode()) {
compare = -1;
}
}
return compare;
顺便说一句,你的对象应该实现 Comparable
接口,并且方法应该被调用 compareTo
.
最后,比较哈希码并不是一个好主意。即使对象不相等,它们也会发生碰撞。这意味着当对象不相等时,您的 compareTo
方法可以 return 0
。这也违反了compareTo
合同。
if (pObject1.hashCode() <= pObject2.hashCode())
{
compare = -1;
} else {
compare = 1;
}
这部分肯定是不兼容compareTo
合约的,好像hash codes是相等的,比较是不相等。相反,你应该使用 return Integer.compare(pObject1.hashCode(), pObject2.hashCode())
,假设你想使用散列码进行比较。 (这通常不是一个好主意,因为哈希码可能会碰巧发生冲突。)
这是我得到的堆栈跟踪
Caused by: java.lang.IllegalArgumentException: Comparison method violates its general contract!
at java.util.TimSort.mergeLo(TimSort.java:777)
at java.util.TimSort.mergeAt(TimSort.java:514)
at java.util.TimSort.mergeCollapse(TimSort.java:441)
at java.util.TimSort.sort(TimSort.java:245)
at java.util.Arrays.sort(Arrays.java:1512)
at java.util.ArrayList.sort(ArrayList.java:1454)
at java.util.Collections.sort(Collections.java:175)
at xxx.sortDisplayFields(OfferFieldLayout.java:521)
这里是比较方法:
public int compare(Field pObject1, Field pObject2)
{
int compare = 0;
//...
if (compare == 0)
{
if (pObject1.hashCode() <= pObject2.hashCode())
{
compare = -1;
}
else
{
compare = 1;
}
}
return compare;
}
我认为这是由于传递性 属性 没有得到尊重: 传递性:如果 A > B 且 B > C,则对于任何 A、B 和 C:A > C。 我试图想出一个反例,但我在这里失败了,感谢任何帮助!
你的函数永远不会return0!这意味着如果对象中的所有内容都相等,包括哈希码,那么 pObject1.compare(pObject2)
将不等于 pObject2.compare(pObject1)
。比较函数必须是对称的。我还认为你在那次测试中交换了 -1
和 1
,所以你最后一次检查应该是这样的:
if (compare == 0) {
if (pObject1.hashCode() < pObject2.hashCode()) {
compare = 1;
} else if (pObject1.hashCode() > pObject2.hashCode()) {
compare = -1;
}
}
return compare;
顺便说一句,你的对象应该实现 Comparable
接口,并且方法应该被调用 compareTo
.
最后,比较哈希码并不是一个好主意。即使对象不相等,它们也会发生碰撞。这意味着当对象不相等时,您的 compareTo
方法可以 return 0
。这也违反了compareTo
合同。
if (pObject1.hashCode() <= pObject2.hashCode())
{
compare = -1;
} else {
compare = 1;
}
这部分肯定是不兼容compareTo
合约的,好像hash codes是相等的,比较是不相等。相反,你应该使用 return Integer.compare(pObject1.hashCode(), pObject2.hashCode())
,假设你想使用散列码进行比较。 (这通常不是一个好主意,因为哈希码可能会碰巧发生冲突。)