equals 和 contains 方法有什么区别

what is the difference between equals and contains methods

我正在使用以下代码处理 TreeSet 集合:

import java.util.*;
public class Employee implements Comparable<Employee>{

    private int ID;

    public Employee(int iD) {
        ID = iD;
    }

    @Override
    public int compareTo(Employee obj) {
        return this.ID-obj.ID;
    }

    private static void intoTreeSet() {
        Employee e1=new Employee(4);
        Employee e2=new Employee(2);
        Employee e3=new Employee(1);
        Employee e4=new Employee(5);
        Employee e5=new Employee(3);

        Employee eTemp=new Employee(3);

        Set<Employee> set=new TreeSet();
        set.add(e1);set.add(e2);set.add(e3);set.add(e4);set.add(e5);

        System.out.println("output says: ");
        for(Employee e:set){
            System.out.print(e.ID+" ~ ");
        }
        System.out.println();
        if(set.contains(eTemp)){
            System.out.println("C O N T A I N S !!!");
        }

        if(e5.equals(eTemp)){
            System.out.println("E Q U A L S !!!");
        }
    }

    public static void main(String[] args) {
        intoTreeSet();
    }
}

输出

output says: 
1 ~ 2 ~ 3 ~ 4 ~ 5 ~ 
C O N T A I N S !!!

我对输出感到困惑。我想知道,如果它没有通过 equals 案例,那么它怎么会通过 contains 案例。

我知道只有当它们的 class 覆盖 equals 方法并且根据某些属性它们是相等的时,两个对象才能相等。我故意没有覆盖 equals 方法来查看 contains 是如何工作的。如果它是一个非基于树的集合,让我们说一个 ArrayList 它不会通过 contains 测试。为什么会这样?谁能解释一下这种行为并消除我的困惑。

The javadoc for java.util.TreeSet 说:

Note that the ordering maintained by a set (whether or not an explicit comparator is provided) must be consistent with equals if it is to correctly implement the Set interface. (See Comparable or Comparator for a precise definition of consistent with equals.) This is so because the Set interface is defined in terms of the equals operation, but a TreeSet instance performs all element comparisons using its compareTo (or compare) method, so two elements that are deemed equal by this method are, from the standpoint of the set, equal. The behavior of a set is well-defined even if its ordering is inconsistent with equals; it just fails to obey the general contract of the Set interface.

也就是说compareToequals的实现必须一致。如果不是,TreeSet 的行为将不稳定。它可能有效,也可能无效。要了解它何时起作用以及何时不需要,您需要仔细查看 TreeSet 实现,但是由于 javadoc 非常明确地说明了 TreeSet 起作用的条件,所以这真的不是一个好主意尝试颠覆它。

这里要记住的最重要的一点是,TreeSet 是一个 SortedSet,它使用 compareTo (or compare) 方法执行元素比较。

员工class 可比。根据可比接口文档的定义,

This interface imposes a total ordering on the objects of each class that implements it. This ordering is referred to as the class's natural ordering, and the class's compareTo method is referred to as its natural comparison method.

因此,如果您的 compareTo 方法 return 和 0,对于相同 class 的两个实例,它们被认为是自然相等的 TreeSet.

文档还说,

It is strongly recommended (though not required) that natural orderings be consistent with equals. This is so because sorted sets (and sorted maps) without explicit comparators behave "strangely" when they are used with elements (or keys) whose natural ordering is inconsistent with equals.

尽管未定义 "strangely" 它的行为方式。

在我们的例子中 e5.equals(eTemp)false,因为 equals 方法没有被覆盖。
e5.compareTo(eTemp)true,所以从集合的角度来看e5eTemp是相等的。

为了演示这一点,您可以执行以下操作:

Employee e1 = new Employee(3);
Employee e2 = new Employee(3);
set.add(e1); // gets added to the set

下面的操作将 return false 因为集合认为 e2 的等价物已经存在于集合中,尽管 e1.equals(e2)false,集合的大小保持不变。

System.out.println(set.add(e2));  // false

为了保持一致,您可以重写 equals 方法,尽管这不是必需的。