【发布时间】:2016-10-06 08:40:38
【问题描述】:
我知道,为了符合 Java 的 Collections 的合同(并避免意外行为),任何提供的 Comparator 都应该与 equals 一致。
假设我有这样的人:
class Person {
private String name;
private String surname;
private int age;
public Person(String name, String surname, int age) {
this.name = name;
this.surname = surname;
this.age = age;
}
public String getName() { return name; }
public String getSurname() { return surname; }
public int getAge() { return age; }
}
比较器是
class PersonComparator implements Comparator<Person> {
@Override
public int compareTo(Person p1, Person p2) {
// throws NPE's
return p1.getName().compareTo(p2.getName());
}
}
现在我想要一些排序的集合(TreeMap,SortedSet,... 无论如何),使用仅比较 Persons 名称的 Comparator。
这个 Comparator 会违反“consistent with equals”契约。但是我不想覆盖equals(Object o),因为在程序的其他部分,两个具有相同姓名、姓氏和年龄的人可能不同(就像在现实生活中一样)。
我希望在所选集合中,名称唯一标识一个人,即TreeSet<Person> 不能有“John Doe”和“John Smith”(同名)。
据我测试,这适用于 Java 集合的当前实现。
我的问题是:你如何“正确”地做到这一点,理想情况下不违反任何合同?如果可能的话,我想避免使用第三方库,当然我不想为了摆脱合同而自己实现数据结构。 我担心我的代码可能会在未来的 Java 版本中中断,因为它违反了合同。
【问题讨论】:
-
a
Comparator不必与 equals 一致。It is generally the case, but <i>not</i> strictly required that <tt>(compare(x, y)==0) == (x.equals(y))</tt>. Generally speaking, any comparator that violates this condition should clearly indicate this fact. The recommended language is "Note: this comparator imposes orderings that are inconsistent with equals." -
如果你的
Person类中的所有数据都不足以清楚地识别一个人,那么你的模型可能不够用。最终,您会遇到多个Person实例代表 same 人的情况。因此,我建议添加一些唯一标识符并在equals()以及您的比较器中使用它。 -
@Thomas “这表明模型可能不足” - 谢谢,我认为这是一个很好的观点。 (我的实际用例完全不同,但我认为这一点可能仍然适用......)
标签: java collections equals