2015-01-04 47 views
1

我的工作与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测试。为什么这样?任何人都可以解释这种行为并清除我的困惑。

+3

“一个TreeSet实例使用其compareTo(或compare)方法执行所有元素比较,因此从该方法看,被这个方法视为相等的两个元素相等。” –

+1

来自几年前的类似问题:http://stackoverflow.com/questions/12761532/equals-and-comparable-with-sets – FoggyDay

+0

http://stackoverflow.com/questions/6476600/ –

回答

3

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

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

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

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

该文件还称,

强烈推荐(虽然不是必需的)使自然排序与 等于一致。这是因为排序集(和排序映射)没有明确的 比较器行为“奇怪”时,它们的自然顺序与等号不一致的元素(或 键)使用。

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

在我们的案例中,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 

因为设置考虑了e2同等已经存在于集合,但e1.equals(e2)false下面的操作将返回false,和集合的大小保持不变。

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

因此,为了保持一致,你可以覆盖equals方法,虽然它是没有必要的。

+0

哇。这是一个很好的解释。毫无疑问,没有混淆,只有更多的知识。谢谢 :) – JPG

6

The javadoc for java.util.TreeSet说:

注意,由一组(无论是否提供了明确的比较器)保持的顺序必须符合等于,如果要正确实现Set接口。 (请参阅Comparable或Comparator以获得与equals一致的精确定义。)这是因为Set接口是根据equals操作定义的,但TreeSet实例使用其compareTo(或compare)方法执行所有元素比较,所以两个从这个方法看,被这个方法认为是相等的元素是相等的。即使排序与等号不一致,集合的行为也是明确定义的;它只是不服从Set接口的总体合同。

换句话说,compareToequals的实现必须相互一致。如果他们不是,TreeSet的行为将是不稳定的。它可能工作,它可能不会。要了解它何时以及何时不需要仔细观察TreeSet的实现,但由于javadoc对TreeSet的工作条件非常明确,因此试图颠覆它并不是一个好主意。

+0

一个历史经典。我已经看到至少有50个标签为'treeset'的问题,它们基本上提出相同的问题并得到相同的(正确的)答案。我想知道为什么这么多人在询问之前不在这里搜索。 ;-) – kriegaex

相关问题