对Java中* any *类的所有实例施加总排序
我不确定以下代码是否可以确保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及更高版本)。只需注意释放比较器即可。