对Java中* any *类的所有实例施加总排序

时间:2020-03-05 18:43:22  来源:igfitidea点击:

我不确定以下代码是否可以确保Comparator Javadoc中给出的所有条件。

class TotalOrder<T> implements Comparator<T> {

    public boolean compare(T o1, T o2) {
        if (o1 == o2 || equal(o1, o2)) return 0;

        int h1 = System.identityHashCode(o1);
        int h2 = System.identityHashCode(o2);

        if (h1 != h2) {
            return h1 < h2 ? -1 : 1;
        }

        // equals returned false but identity hash code was same, assume o1 == o2
        return 0;
    }

    boolean equal(Object o1, Object o2) {
        return o1 == null ? o2 == null : o1.equals(o2);
    }
}

即使该类未实现Comparable,以上代码是否会对所有类的所有实例强加全部排序?

解决方案

回答

我们在评论中回答:

equals returned false but identity hash code was same, assume o1 == o2

不幸的是,我们不能假设这一点。在大多数情况下,这是可行的,但在某些例外情况下,它将不起作用。而且你不知道什么时候。当出现这种情况时,例如,它将导致TreeSet中的实例丢失。

回答

我不认为是因为没有满足此子句:

Finally, the implementer must ensure that x.compareTo(y)==0 implies that sgn(x.compareTo(z)) == sgn(y.compareTo(z)), for all z.

由于equal(o1,o2)取决于o1的equals实现,因此逻辑上相等的两个对象(由equals确定)仍然具有两个不同的identityHashCodes。

因此,当将它们与第三个对象(z)进行比较时,它们最终可能会为compareTo产生不同的值。

有道理?

回答

我不太确定System.identityHashCode(Object)。这几乎就是==的用途。我们可能更想使用Object.hashCode(),它与Object.equals(Object)更加并行。

回答

如果到达最后的" return 0"行,则可能会引发异常-发生哈希冲突时。不过,我确实有一个问题:我们正在对散列进行总排序,我想这很好,但是不应该将某些函数传递给它来定义词典顺序吗?

int h1 = System.identityHashCode(o1);
    int h2 = System.identityHashCode(o2);
    if (h1 != h2) {
        return h1 < h2 ? -1 : 1;
    }

我可以想象我们有两个整数组成一个实数的元组的对象。但是,由于仅获取对象的哈希值,因此我们将无法获得正确的排序。如果散列是意思,这完全取决于我们,但是对我而言,这没有多大意义。

回答

I agree this is not ideal, hence the comment. Any suggestions?

我认为现在有一种方法可以解决该问题,因为我们无法访问可以区分两个实例的一件事和一件事:它们在内存中的地址。因此,我只有一个建议:重新考虑我们对使用Java进行总体订购的需求:-)

回答

嘿,看看我发现了什么!

http://gafter.blogspot.com/2007/03/compact-object-comparator.html

这正是我想要的。

回答

Hey, look at what I found!
  
  http://gafter.blogspot.com/2007/03/compact-object-comparator.html

哦,是的,我忘记了IdentityHashMap(仅Java 6及更高版本)。只需注意释放比较器即可。