使用与 equals() 不一致的比较器聚合相似对象

Aggregating similar objects using comparator without consistency with equals()

我有一组实现 equals() 的不可变对象,它们严格比较它们持有的成员变量。如果成员变量相等,则两个对象相同。 hashCodes()与此一致。

我希望能够根据更宽松的相似性定义来聚合这些对象。我正在考虑为此使用比较器,以便我可以定义一堆临时相似性规则,但 javadoc 指出比较器应该与 equals() 一致。是否可以打破与 equals() 的比较器合同来实现这一点,或者是否有更好的 method/pattern/strategy 根据一些相似性规则聚合对象?

示例可能包括:

考虑到"similarity"不是传递操作:如果a类似于b,并且b类似于c,那么a可能类似于c,这里建议不要用Comparable/Comparator,因为它的契约隐含了传递性。

适合您需要的自定义界面应该是一个不错的选择:

interface SimilarityComparable<T, D> {
    // D - object that represents similarity level
    D getSimilarityLevel(T other);
}

但是,由于 Java 泛型:

,使用这种方法您将无法为同一类型定义多组相似性
class Location implements SimilarityComparable<Location, Distance>, SimilarityComparable<Location, NameDifference> {
    // won't compile - can't use two generic interfaces of the same type simultaneously
}

在这种情况下,您可以回退到比较器:

interface SimilarityComparator<T, D> {
    D getSimilarityLevel(T a, T b);
}

class LocationDistanceSimilarityComparator implements SimilarityComparator<Location, Distance> { 
    ... 
}

class LocationNameSimilarityComparator implements SimilarityComparator<Location, NameDifference> { 
    ... 
}

答案将取决于您打算如何使用比较。

但是,我同意@user3707125,在任何情况下都不要为此目的实施Comparable。您无法控制哪些代码将使用 Comparable 函数进行必须遵循定义的规则的比较。

在某些情况下您 必须 使用 Comparator,例如如果您使用标准 Java API 库来排序或过滤你的对象。如果是这种情况,那么您仍然可以安全地使用 Comparator,因为您可以控制在何处使用 Comparator,以及在何处使用更严格的 equals()。您只需要注意,如果您的宽松比较不符合标准合同,那么排序和筛选操作将产生同样宽松且不一致的结果。

如果您不必使用 Comparator 那么就不要使用。您可以自由定义自己的方法和接口,以您喜欢的任何方式做任何您想做的事。打败自己!