可比接口取决于大小?

时间:2017-06-02 05:45:28

标签: java comparable

我正在使用Comparable界面,发现当我将IllegalArgumentException放入下面的程序时它正在抛出size=50,当我放置size =5时工作正常。

    public class Test {
    public static void main(String[] args) {
        int size = 50;
        Test compareTest = new Test();
        compareTest.test(size);
    }

    public void test(int size) {
        List<TestObject> requests = new ArrayList<TestObject>();
        for (int index = 0; index < size; index++) {
            TestObject request = new TestObject();
            request.value = index;
            requests.add(request);
        }
        Collections.sort(requests);
    }

}

class TestObject implements Comparable<TestObject> {
    public int value;

    public int compareTo(TestObject req) {
        if (value % 3 == 0) {
            return -1;
        } else if (value % 3 == 1) {
            return 0;
        }

        return 1;
    }
}

我不确定这个问题的根本原因,有人可以帮我解决这个问题。

下面给出了异常堆栈跟踪。

Exception in thread "main" java.lang.IllegalArgumentException: Comparison method violates its general contract!
    at java.util.ComparableTimSort.mergeLo(ComparableTimSort.java:744)
    at java.util.ComparableTimSort.mergeAt(ComparableTimSort.java:481)
    at java.util.ComparableTimSort.mergeCollapse(ComparableTimSort.java:406)
    at java.util.ComparableTimSort.sort(ComparableTimSort.java:213)

2 个答案:

答案 0 :(得分:6)

您违反了可比较合同。

实际上你不比较它们之间的两个对象,但你只根据3的模数结果比较当前value对象的TestObject字段。你不使用{{ 1}}对象在TestObject方法中作为参数传递。

假设您有compareTo()ListTestObject个对象3value字段

这两个对象将返回-1

    if (value % 3 == 0) {
        return -1;
    } 

但根据规则:

  

实现者必须确保sgn(x.compareTo(y))==   -sgn(y.compareTo(x))表示所有x和y。 (这意味着如果y.compareTo(x)抛出一个x.compareTo(y)必须抛出异常   异常。)

假设第一个对象是x而第二个对象是y 如果y.compareTo(x)返回负数(例如-1),那么x.compareTo(y)应返回正数(例如1)。

  

我正在使用Comparable接口,发现它正在抛出   当我在下面的程序中输入size = 50时,IllegalArgumentException   当我把size = 5

时工作正常

事实上,当您违反Comparable合同时,结果无法预测。它可能与某些特定值一起使用,不适用于其他特定值 它可能在特定的JVM版本中工作,而在另一个版本中不起作用 试图理解它失败的原因或者它对特定值的成功可能很有意思,但实际上没有用。
为了尊重合同,试图理解合同要好得多。 因为今天它的工作正在进行中,但明天在未来的实施中,它可能会改变。只有API才是保证。

答案 1 :(得分:2)

出现此错误是因为compareTo不是合法比较功能。

compareTo必须遵守等价(等式)和排序的数学规则:

(1)x.compareTo(x)必须返回0.

(2)如果x.compareTo(y)返回0,则y.compareTo(x)返回0;如果x.compareTo(y)返回&gt; 0,则y.compareTo(x)返回&lt; 0,反之亦然。

(3)如果x.compareTo(y)y.compareTo(z)都返回&gt; 0,那么x.compareTo(z)也会返回&gt; 0;类似地,如果它们都是0,或者它们都是&lt; 0(传递性)。以上简化了一点。

你的比较函数甚至没有查看它的参数; compareTo应该将一个对象与另一个对象进行比较,但是您的函数完全忽略了第二个参数。这清楚地表明您的比较函数将违反所有这三个条件。

Timsort有时会在违反合同时发出通知;如果它已经看过compareTo如何对某些值起作用,它可能会推断它应该对以前看到的值有某种特定的行为方式。如果compareTo返回它不期望的内容,则会抛出异常。大多数排序算法都不会寻找这种违规行为。但是如果它们被赋予了不遵守规则的比较函数,那么结果可能是一个相当随机的顺序,或者它可能会使算法陷入无限循环。