我正在使用以下代码处理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
测试。为什么会这样?任何人都可以解释这种行为并清除我的困惑。
答案 0 :(得分:6)
The javadoc for java.util.TreeSet
说:
请注意,如果要正确实现Set接口,则由一个集维护的排序(无论是否提供显式比较器)必须与equals 一致。 (有关与equals一致的精确定义,请参阅Comparable或Comparator。)这是因为Set接口是根据equals操作定义的,但TreeSet实例使用compareTo(或compare)方法执行所有元素比较,因此从集合的角度来看,通过这种方法被认为相等的元素是相等的。集合的行为即使其排序与equals不一致也是明确定义的;它只是没有遵守Set接口的一般合同。
换句话说,compareTo
和equals
的实现必须相互一致。如果他们不这样做,TreeSet
的行为就会不稳定。 可以工作,也可能不工作。要了解它何时发生以及何时发生,您需要仔细查看TreeSet
实现,但由于javadoc对TreeSet
的工作条件非常明确,因此它是&#39;尝试颠覆它并不是一个好主意。
答案 1 :(得分:3)
要记住的最重要的一点是,TreeSet
是SortedSet,它使用compareTo (or compare)
方法执行元素比较。
Employee类可比较。根据可比较界面的文档定义,
此接口对每个类的对象施加总排序 实现它。这种排序称为类 自然排序,类的 compareTo方法称为 它的自然比较方法。
因此,如果您的compareTo
方法返回0
,则对于同一类的两个实例,它们被TreeSet
视为自然相等。
该文件还说,
强烈建议(尽管不要求)自然排序与之一致 等于。这是因为排序集(和有序映射)没有显式 比较器与元素一起使用时表现得“奇怪”(或 键)其自然顺序与equals不一致。
虽然没有定义它的行为有多“奇怪”。
我们的情况e5.equals(eTemp)
为false
,因为equals
方法未被覆盖。
e5.compareTo(eTemp)
为true
,因此从集合的角度e5
和eTemp
相等。
为了证明这一点,您可以执行以下操作:
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}}方法,尽管没有必要。