2

我试图在论坛中回答这个问题,我发现尽管重写了类中的equals方法Employee,我仍然能够向TreeSet.

TreeSet.add(E)方法的 Javadoc说

如果指定的元素尚不存在,则将其添加到此集合中。更正式地说,如果集合不包含元素 e2,则将指定的元素 e 添加到此集合中,使得 (e==null ? e2==null : e.equals(e2))。如果该集合已包含该元素,则调用将保持该集合不变并返回 false。

这实质上意味着不会插入 2 个等于对象TreeSet,并且相等性仅由equals()包含对象的方法确定。

但是,下面的代码添加了 2 个元素,Set即使它们相等

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

4

3 回答 3

9

TreeSet 的 javadoc 还说:

请注意,如果要正确实现接口,集合维护的顺序(无论是否提供显式比较器)必须与 equals 一致。Set(有关与 equals 一致的精确定义,请参见Comparableor 。)这是因为接口是根据操作定义的,但实例使用其(or ) 方法执行所有元素比较,因此两个元素被视为相等从集合的角度来看,方法是相等的。一个集合的行为明确定义的,即使它的顺序与equals不一致;它只是不遵守接口的一般合同。ComparatorSetequalsTreeSetcompareTocompareSet

我同意 javadocadd()可以更清楚地说明equals()没有实际使用的内容,并重新声明或链接到此警告。

于 2013-07-12T07:16:41.753 回答
0

Set实现Map在幕后使用 a 来管理数据,并在这样做时通过Map's 键保证对象的唯一性。

据我所知,没有进行明确的测试,equals这意味着如果您的对象不是明确的同一对象(即'=='),则会添加它。

我认为这些文档具有误导性,但我猜它是在说它是正式的语言表示。这是模棱两可的,所以我可能是错的,但我很确定唯一性是通过底层映射的键来保证的。仅供参考:以您的对象为键传递一个虚拟值。

于 2013-07-12T07:26:20.797 回答
0

关于 TreeSet 的第一件事是,它还保持对象的顺序,同时对它们进行排序并使用 compareTo 方法。

因为在您的 compareTo 方法的第一个版本中,您使用employeeId 进行比较,并为对象e1 和e2 放置不同的emplyee id。

Treeset 会将其视为不同的对象,因为比较不会发送零值(它将发送 + 或 - 值)。

但是在第二个版本中,您使用employeeName 来实现compareTo,这对于对象e1 和e2 是相同的。

于 2013-07-12T08:43:29.590 回答