等于具有可比接口的方法合同

时间:2014-06-17 19:12:33

标签: java collections equals comparable

我有像Person这样的自定义类:

public class Person {
    int age;
    String name;
}

现在我想根据Personage类对象进行排序。

所以我将使用Comparable接口并实现compareTo()方法。

并且compareTo将具有基于age比较人物对象的逻辑。

所以,如果我这样做:

Collections.sort(list);  // where list is a list of person

我将根据age获得排序人员列表。

但是我在某处读到了,当我们执行equals()时,我们也需要覆盖Comparable方法。

但我现在还没有看到它的使用。

任何人都可以解释一下,如果我只想基于equals() sort来覆盖age方法吗?

4 个答案:

答案 0 :(得分:7)

没有法律涉及Comparable.compareTo()equals()。但是,如果compaeTo()返回0equals()返回false,我会说这很令人困惑。

我认为在您的情况下,您应该使用自定义比较器,而不是使您的类Comparable。原因是今天你的比较标准是年龄,明天它将是人的名字,然后是姓氏,然后是权重......等等。这就是Comparator被引入的原因和用例的时候它应该被使用。

答案 1 :(得分:6)

来自Comparable的javadoc:

  

强烈建议(尽管不要求)自然   订单[即由Comparable.compareTo]定义的排序与equals一致。这是因为排序集   没有显式比较器的(和排序的地图)表现得“奇怪”   它们与自然顺序的元素(或键)一起使用   与equals不一致。特别是,这样的排序集(或排序的   map)违反了定义的集合(或映射)的一般合同   就平等方法而言。

“与equals一致”表示compareTo当且仅当equals返回true时才返回0。因此,除非compareTo始终为两个不同的对象引用返回值!= 0,否则应覆盖equals

答案 2 :(得分:5)

您不需要覆盖等号,因为Collections.sort()将使用compareTo(),而不是equals()。但是,覆盖它通常是一个好主意。

答案 3 :(得分:2)

只是详细说明为什么compareTo()和equals()需要保持一致。 Sorted Set取决于Object的compareTo()方法,以了解是否可以在集合中添加特定元素,并避免将重复元素添加到集合中。因此,如果是这种情况,则会导致歧义(从规范中复制): -

  

例如,如果添加两个键a和b使得(!a.equals(b)&& a.compareTo(b)== 0)到一个不使用明确的   比较器,第二个add操作返回false(和大小   排序集不会增加)因为a和b是等价的   排序集的视角。

详细说明,排序集使用了compareTo()来检查两个元素a& b是否相等,如果是& b只覆盖compareTo()方法而不是equals()方法,那么我们可以有一个场景,其中compareTo()方法返回0,但equals()方法返回false,这是非常奇怪和不一致的。我们假设我有一个Name类,如下所示: -

proguardFiles

}

public class Name implements Comparable<Name> {
private final String firstName, lastName;

public Name(String firstName, String lastName) {
    if (firstName == null || lastName == null)
        throw new NullPointerException();
    this.firstName = firstName;
    this.lastName = lastName;
}

public String firstName() {
    return firstName;
}

public String lastName() {
    return lastName;
}

/*public boolean equals(Object o) {
    if (!(o instanceof Name))
        return false;
    Name n = (Name) o;
    return n.firstName.equals(firstName) && n.lastName.equals(lastName);
}

public int hashCode() {
    return 31 * firstName.hashCode() + lastName.hashCode();
}*/

public String toString() {
    return firstName + " " + lastName;
}

public int compareTo(Name n) {
    int lastCmp = n.lastName.compareTo(lastName);
    return (lastCmp != 0 ? lastCmp : n.firstName.compareTo(firstName));
}

输出如下所示: -

        // Tester class main method has the below code
        Name n1 = new Name("John", "Smith");
        Name n2 = new Name("John", "Smith");

        SortedSet<Name> mySet = new TreeSet<>();

        System.out.println(mySet.add(n1));
        System.out.println(n1.equals(n2));
        System.out.println(n1.compareTo(n2));
        System.out.println(mySet.add(n2));

现在这显示了模糊性,因为我们没有覆盖equals(),在这种情况下返回false,但compareTo()返回0,因此SortedSet认为两个对象n1和n2相等,因此添加了n2进入Set返回false,如sysout所示,但它们不相等!!!

有关详情,请参阅stackoverflow链接: - Comparator and equals()