使用比较器聚合类似对象而不与equals()

时间:2015-07-01 10:50:07

标签: java

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

我希望能够根据相似性的宽松定义聚合这些对象。我正在考虑使用比较器,以便我可以定义一组特殊的相似性规则,但是javadoc声明比较器应该与equals一致。可以用equals()打破比较器契约来实现这一点,还是有一些更好的方法/模式/策略来根据一些相似性规则聚合对象?

示例可能包括:

  • 位置:如果LatLng和地名完全相等,则equals()返回true,但如果LatLng在25m / 50m / 100m之内,比较器返回0,无论地名等,或者只有地名等于LatLng。
  • 日期:如果long millis相等,则equals()返回true,但如果在同一天/月/年等,比较器返回0 ..
  • 字符串:如果equalsIgnoreCase为true,则equals返回true,但是比较器可能会删除空格/特殊字符以减少某些规范形式,然后运行等于等。

非常感谢, RIZ

2 个答案:

答案 0 :(得分:0)

考虑到“相似性”不是传递操作:如果 a 类似于 b b 类似于 c ,然后 a 可能 c 类似,我建议不要使用Comparable / {{ 1}}这里,因为它的契约意味着传递性。

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

Comparator

然而,使用这种方法,由于Java泛型,您将无法为同一类型定义多个相似性组:

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

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

class Location implements SimilarityComparable<Location, Distance>, SimilarityComparable<Location, NameDifference> {
    // won't compile - can't use two generic interfaces of the same type simultaneously
}

答案 1 :(得分:0)

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

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

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

如果您不必使用Comparator,请不要。你可以自由地定义自己的方法和接口,以任何你喜欢的方式做任何你想做的事情。自己敲门!