可比接口取决于大小?

Comparable interface depends upon size?

我正在处理 Comparable 接口,发现当我在下面的程序中放入 size=50 时它抛出 IllegalArgumentException 并且当我放入 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)

您违反了可比合同。

其实你并没有比较两个对象之间的关系,你只是根据对3取模的结果比较了当前TestObject对象的value字段。你没有使用TestObject 对象在 compareTo() 方法中作为参数传递。

假设您有一个 List 的两个 TestObject 对象,其中 3 作为 value 字段

两个对象会 return -1 :

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

但是根据规则:

The implementor must ensure sgn(x.compareTo(y)) == -sgn(y.compareTo(x)) for all x and y. (This implies that x.compareTo(y) must throw an exception iff y.compareTo(x) throws an exception.)

假设第一个对象是x,第二个对象是y
如果y.compareTo(x)return是负数(比如-1),那么x.compareTo(y)应该return是正数(比如1)。

I was working on Comparable interface and found that it is throwing IllegalArgumentException when i put size=50 in the program below and is working fine when i put size =5

事实上,当你违反Comparable合同时,结果是不可预测的。它可能适用于某些特定值,不适用于其他特定值。
它可能适用于特定的 JVM 版本,但不适用于其他版本。
试图理解为什么它失败或成功的特定值可能很有趣,但实际上没有帮助。
努力理解合同以尊重它要好得多。 因为今天它正在运行,但明天在未来的实施中,它可能会改变。只有API是保证。

出现此错误是因为 compareTo 不是合法的比较函数。

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

(1) x.compareTo(x) 必须 return 0.

(2) 如果x.compareTo(y) returns 0, y.compareTo(x) returns 0;如果 x.compareTo(y) returns >0,y.compareTo(x) returns <0,反之亦然。

(3) 如果x.compareTo(y)y.compareTo(z)都return>0,则x.compareTo(z)也return>0;类似地,如果它们都为 0,或者它们都 < 0(传递性)。以上略作简化。

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

Timsort 有时会在合同被违反时注意到;如果它已经查看了 compareTo 如何处理某些值,它可能会推断它应该以某种方式处理它之前看到的值。如果 compareTo return 是它不期望的东西,它会抛出异常。大多数排序算法不会寻找这种违规行为。但是如果给他们一个不遵守规则的比较函数,结果可能是一个相当随机的顺序,或者它可能会使算法陷入无限循环。