我试图在论坛中回答this问题,但我发现尽管覆盖了equals
类中的Employee
方法,但我仍然能够将重复的元素添加到TreeSet
。
TreeSet.add(E)方法的Javadoc说
如果指定的元素尚不存在,则将其添加到此集合中。 更正式地说,如果集合,则将指定的元素e添加到此集合中 不包含元素e2(e == null?e2 == null:e.equals(e2))。 如果此集合已包含该元素,则该调用将离开该集合 不变并返回false。
这实质上意味着没有2个等于对象将被插入TreeSet
,并且相等仅由所包含对象的equals()
方法确定。
但是,下面的代码是向Set
添加2个元素,即使它们相等
public class Employee implements Comparable<Employee> {
String employeeName;
int employeeId;
public Employee(String name, int id) {
this.employeeName = name;
this.employeeId = id;
}
public int compareTo(Employee emp) {
//return this.employeeName.compareTo(emp.employeeName);
return (this.employeeId - emp.employeeId);
}
@Override
public String toString() {
return ("Name is: " + employeeName + " Emp id is: " + employeeId);
}
@Override
public boolean equals(Object emp) {
if(emp instanceof Employee &&((Employee)emp).employeeName.equals(this.employeeName)){
return true;
}
return false;
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Set<Employee> set = new TreeSet<Employee>();
Employee e1 = new Employee("A", 1);
Employee e2 = new Employee("A", 2);
System.out.println(e1.equals(e2));
set.add(e1);
set.add(e2);
System.out.println(set);
}
}
这是输出
true
[Name is: A Emp id is: 1, Name is: A Emp id is: 2]
为什么TreeSet
允许多个元素,即使它们相等?
现在我改变了compareTo
这样的Employee
方法
public int compareTo(Employee emp) {
return this.employeeName.compareTo(emp.employeeName);
}
输出
true
[Name is: A Emp id is: 1]
覆盖TreeSet
后compareTo
如何正常工作?
答案 0 :(得分:9)
TreeSet的javadoc也说:
请注意,如果要正确实现
Set
接口,则由集合维护的排序(无论是否提供显式比较器)必须与equals 一致。 (有关与equals 一致的精确定义,请参阅 Comparable
或Comparator
。)这是因为Set
接口是根据{{1操作,但是equals
实例使用其TreeSet
(或compareTo
)方法执行所有元素比较,因此从这个方法看,两个被认为相等的元素是设定,平等。集合的行为定义良好,即使它的排序与equals不一致;它只是不遵守compare
接口的一般合同。
我同意Set
的javadoc可以更清楚地表明add()
实际上并未使用,并重新陈述或链接到此警告。
答案 1 :(得分:0)
Set
实现在后台使用Map
来管理数据,并在此过程中通过Map
的密钥保证对象的唯一性。
据我所知,没有对equals
进行明确的测试,这意味着如果你的对象不是明确相同的对象(即'=='),你的对象就会被添加。
我认为这些文档具有误导性,但我猜这是说它是正式的语言表达。这是不明确的,所以我可能是错的,但我很确定凭借底层地图的密钥保证了唯一性。仅供参考:以对象为键传递虚拟值。
答案 2 :(得分:0)
关于TreeSet的第一件事是,它还在stroing它们时保持对象的顺序并使用compareTo方法。
因为在你的第一个compareTo方法版本中,你使用employeeId进行比较,并为对象e1和e2添加了不同的emoplyee id。
Treeset会将此视为不同的对象,因为比较不会发送零值(它将发送+或 - 值)。
但在第二个版本中,您使用employeeName实现compareTo,对于对象e1和e2,它是相同的。