我能够在TreeSet中插入重复的条目。如何克服这一点

时间:2013-07-12 06:06:19

标签: java treeset

我有一个名为Employee的类,它有employeeNameemployeeId作为其成员变量。我正在创建新的Employee对象,然后将其添加到TreeSet我要对其进行排序基于employeeId。但是如果它们具有相同的employeeName,我认为2个Employee对象是相同的。设置不允许重复。但在这里我可以观察到一种奇怪的行为。这是我的代码。(我这里没有使用getter和setter。我直接访问成员变量。)

package secondOne;

import java.util.Set;
import java.util.TreeSet;

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 == this.employeeName) {
            return true;
        }
        return false;
    }

}

public class TestingSetsWithComparable {
    /**
     * @param args
     */
    public static void main(String[] args) {
        Employee e1 = new Employee("A", 1);
        Employee e2 = new Employee("A", 2);
        Employee e3 = new Employee("B", 3);

        Set<Employee> set = new TreeSet<Employee>();
        set.add(e1);
        set.add(e2);
        set.add(e3);
        System.out.println(set);
    }
}

这里上面代码的输出是,
[Name is: A Emp id is: 1, Name is: A Emp id is: 2, Name is: B Emp id is: 3]

我的第一个问题是,在equals()方法中,如果他们有相同的employeeName,我认为2个Employee objests是相等的但是在compareTo方法中,我使用employeeId进行排序。在这种情况下,输出显示employeeName'A'的2个条目。当我认为2个对象具有相同的employeeName时,TreeSet如何允许重复条目。这怎么可能..? 第二个问题是,在compareTo方法中,如果我使用employeeName进行排序,那么我不会得到同名的第二个重复条目。第二种情况的输出是
[Name is: A Emp id is: 1, Name is: B Emp id is: 3]

为什么会这样..?

3 个答案:

答案 0 :(得分:8)

问题在于:

((Employee)emp).employeeName== this.employeeName

您必须使用String方法比较equals

((Employee)emp).employeeName.equals(this.employeeName)

请参阅How do I compare strings in Java?

此外,由于您要覆盖equals方法,因此如果您覆盖hashCode方法也是一件好事,如Object#equals合同中所述:

  

请注意,通常需要在重写此方法时覆盖hashCode方法,以便维护hashCode方法的常规协定,该方法声明相等的对象必须具有相同的哈希代码。

其他:由于您使用的是TreeSet,因此它将使用compareTo方法,而不是equalshashCode方法。这是因为TreeSet实现了SortedSet接口。请参阅SortedSet javadoc(强调我的):

  

进一步提供其元素的总排序的集合。元素按使用natural ordering(即实施Comparable<T>或通常在排序集创建时提供的Comparator进行排序。

您应该根据您的需要实施此方法:

public int compareTo(Employee emp) {
    if (this.employeeName.equals(emp.employeeName)) {
        return 0;
    }
    //removed the comparison by subtraction since it will behave wrongly on int overflow
    return new Integer(this.employeeId).compareTo(emp.employeeId);
}

由于您正在比较字符串,我建议使用StringUtils中的Apache Commons Lang类来提供帮助方法以避免null检查和其他方法。

答案 1 :(得分:1)

你应该比较 string而不是 == ,但使用equals()方法,你也应该覆盖compareTo employeeName进行比较的方法,如果您希望以这种方式进行比较。

employeeId

(Employee)emp).employeeName.equals(this.employeeName)

答案 2 :(得分:0)

你比较字符串的方式是错误的。见How to compare 2 Strings in Java

(Employee)emp).employeeName== this.employeeName

应该是

(Employee)emp).employeeName.equals(this.employeeName)