"same ordering" 个对象相等的重要性是什么?

What is the importance of "same ordering" objects being equal?

我正在对一组对象进行排序。这些对象有很多字段,但我只关心其中一个。所以,我写了一个比较器:

    Collections.sort(details, new Comparator<MyObj>() {
        @Override
        public int compare(MyObj d1, MyObj d2) {
            if (d1.getDate() == null && d2.getDate() == null) {
                return 0;
            } else if (d1.getDate() == null) {
                return -1;
            } else if (d2.getDate() == null) {
                return 1;
            }

            if (d1.getDate().before(d2.getDate())) return 1;
            else if (d1.getDate().after(d2.getDate())) return -1;
            else return 0;
        }
    });

从我的用例的角度来看,这个 Comparator 做了它需要做的一切,即使我可能认为这种排序是不确定的。但是,我想知道这是否是错误的代码。通过这个 Comparator,两个非常不同的对象可以被认为是 "the same" 排序,即使它们是不相等的对象。我决定使用 hashCode 作为决胜局,结果是这样的:

    Collections.sort(details, new Comparator<MyObj>() {
        @Override
        public int compare(MyObj d1, MyObj d2) {

            if (d1.getDate() == null && d2.getDate() == null) {
                return d1.hashCode();
            } else if (d1.getDate() == null) {
                return -1;
            } else if (d2.getDate() == null) {
                return 1;
            }

            if (d1.getDate().before(d2.getDate())) return 1;
            else if (d1.getDate().after(d2.getDate())) return -1;
            else return d1.hashCode() - d2.hashCode();
        }
    });

(我return可能是倒过来的,但这对这个问题并不重要)

有这个必要吗?

编辑: 对于其他查看此问题的人,请考虑使用 Google 的排序 API。上面的逻辑被替换为:

 return Ordering.<Date> natural().reverse().nullsLast().compare(d1.getDate(), d2.getDate());

Through this comparator, two very distinct objects could be considered "the same" ordering even if they are unequal objects.

那真的没关系;两个对象 比较 完全相等,即使它们在任何其他意义上都不是 "equal"。 Collections.sort 是一种 稳定的 排序,这意味着比较相等的对象按照它们进来的相同顺序出现;这相当于只使用 "the index in the input" 作为决胜局。

(此外,您的新 Comparator 实际上比原来的更糟糕。return d1.hashCode() 特别荒谬,并且 return d1.hashCode() - d2.hashCode() 会导致非传递排序,这会破坏 Collections.sort,因为溢出问题。除非两个整数都绝对是非负的,否则 hashCode 不是,总是使用 Integer.compare 来比较整数。)

这仅在对象 implement Comparable.

时才最重要

It is strongly recommended (though not required) that natural orderings be consistent with equals. This is so because sorted sets (and sorted maps) without explicit comparators behave "strangely" when they are used with elements (or keys) whose natural ordering is inconsistent with equals. In particular, such a sorted set (or sorted map) violates the general contract for set (or map), which is defined in terms of the equals method.

For example, if one adds two keys a and b such that (!a.equals(b) && a.compareTo(b) == 0) to a sorted set that does not use an explicit comparator, the second add operation returns false (and the size of the sorted set does not increase) because a and b are equivalent from the sorted set's perspective.

但是,您并没有这样做,您使用的是自定义 Comparator,可能是出于展示原因。由于此排序指标并非固有地附加到对象,因此无关紧要。


顺便说一句,为什么不只是 return 0 而不是乱用 hashCodes?然后,如果日期匹配,他们将保留 原始顺序 ,因为 Collections.sort 是一个 stable sort. I agree with ,以这种方式使用 hashCode 可能会产生非常奇怪的后果,主要是相关的到整数溢出。考虑 d1.hashCode() 为正且 d2.hashCode() 为负的情况,反之亦然。