Can/should一个写一个与Object的equals方法一致的Comparator

Can/should one write a Comparator consistent with Object's equals method

我有一个对象,Foo,它从 Object 继承了默认的 equals 方法,我不想覆盖它,因为引用相等性是我认为的身份关系想用。

我现在有一个特定的情况,我现在想根据特定的领域来比较这些对象。我想编写一个比较器 FooValueComparator 来执行此比较。但是,如果我的 FooValueComparator returns 0 每当两个对象对该特定字段具有相同的值时,那么它与从 Object 继承的 equals 方法不兼容,以及随之而来的所有问题。

我想做的是 FooValueComparator 首先比较两个对象的字段值,然后再比较它们的引用。这可能吗?这可能会带来什么陷阱(例如,内存位置的改变导致 Foo 对象的相对顺序发生改变)?

我希望我的比较器与 equals 兼容的原因是因为我希望可以选择将它应用于 Foo 个对象的 SortedSet 集合。我不希望 SortedSet 拒绝我尝试添加的 Foo,因为它已经包含具有相同值的不同对象。

这在 Comparator 的文档中有描述:

The ordering imposed by a comparator c on a set of elements S is said to be consistent with equals if and only if c.compare(e1, e2)==0 has the same boolean value as e1.equals(e2) for every e1 and e2 in S.

Caution should be exercised when using a comparator capable of imposing an ordering inconsistent with equals to order a sorted set (or sorted map). Suppose a sorted set (or sorted map) with an explicit comparator c is used with elements (or keys) drawn from a set S. If the ordering imposed by c on S is inconsistent with equals, the sorted set (or sorted map) will behave "strangely." In particular the sorted set (or sorted map) will violate the general contract for set (or map), which is defined in terms of equals.

简而言之,如果 Comparator 的实现与 equals 方法不一致,那么你应该知道你在做什么,并且你要为这个设计的副作用负责,但是让实现与 Object#equals 一致并不是强加的。尽管如此,还是要考虑到最好这样做,以免给将来维护系统的编码人员造成混淆。类似的概念适用于实施 Comparable.

JDK 中的示例可以在 BigDecimal#compareTo 中找到,它在 javadoc 中明确指出此方法与 BigDecimal#equals.

不一致

如果您打算使用 SortedSet<YourClass>,那么您可能使用了错误的方法。我建议改用 SortedMap<TypeOfYourField, Collection<YourClass>>(或 SortedMap<TypeOfYourField, YourClass>,以防同一键没有 equals 元素)。它可能需要做更多的工作,但它可以让您更好地控制数据 stored/retrieved in/from 结构。

对于给定的 class,您可能有多个比较器,即每个不同的领域。
在这种情况下,不能重复使用 equals。因此答案是不一定。但是,如果您的集合存储在排序的(映射或树)中并且使用比较器来确定该集合中的元素位置,则您应该使它们保持一致。

详情见documentation