equals和contains方法之间有什么区别

时间:2015-01-04 03:16:08

标签: java collections treeset

我正在使用以下代码处理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案例。

我知道如果两个对象的类重写equals方法并且根据某些属性它们相等,则它们只能相等。我故意没有覆盖equals方法来查看contains的工作方式。如果它是一个非基于树的集合,可以说ArrayList它不会通过contains测试。为什么会这样?任何人都可以解释这种行为并清除我的困惑。

2 个答案:

答案 0 :(得分:6)

The javadoc for java.util.TreeSet说:

  

请注意,如果要正确实现Set接口,则由一个集维护的排序(无论是否提供显式比较器)必须与equals 一致。 (有关与equals一致的精确定义,请参阅Comparable或Comparator。)这是因为Set接口是根据equals操作定义的,但TreeSet实例使用compareTo(或compare)方法执行所有元素比较,因此从集合的角度来看,通过这种方法被认为相等的元素是相等的。集合的行为即使其排序与equals不一致也是明确定义的;它只是没有遵守Set接口的一般合同。

换句话说,compareToequals的实现必须相互一致。如果他们不这样做,TreeSet的行为就会不稳定。 可以工作,也可能不工作。要了解它何时发生以及何时发生,您需要仔细查看TreeSet实现,但由于javadoc对TreeSet的工作条件非常明确,因此它是&#39;尝试颠覆它并不是一个好主意。

答案 1 :(得分:3)

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

Employee类可比较。根据可比较界面的文档定义,

  

此接口对每个类的对象施加总排序   实现它。这种排序称为类   自然排序,类的 compareTo方法称为   它的自然比较方法。

因此,如果您的compareTo方法返回0,则对于同一类的两个实例,它们被TreeSet视为自然相等。

该文件还说,

  

强烈建议(尽管不要求)自然排序与之一致   等于。这是因为排序集(和有序映射)没有显式   比较器与元素一起使用时表现得“奇怪”(或   键)其自然顺序与equals不一致。

虽然没有定义它的行为有多“奇怪”。

我们的情况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

以下操作将返回false,因为该集合认为该集合中已存在等效e2,但e1.equals(e2)false,且大小为System.out.println(set.add(e2)); // false 集合保持不变。

equals

为了保持一致,你可以覆盖{{1}}方法,尽管没有必要。