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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17608422/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-01 02:27:39  来源:igfitidea点击:

I am able to insert duplicate entries in TreeSet. How to overcome this

javatreeset

提问by Prasad

I have a class called Employee which has employeeNameand employeeIdas its member variables.I am creating new Employee objects and then adding it into a TreeSetwhere I want to sort it based on the employeeId. But I consider 2 Employee objects to be equal if they have the same employeeName. Set does not allow duplicates. But here I can observe a strange behavior. This is my code.(I am not using getters and setters here. I am directly accessing the member variables.)

我有一个名为 Employee 的类,它具有employeeNameemployeeId作为其成员变量。我正在创建新的 Employee 对象,然后将其添加到TreeSet我想根据employeeId. 但是我认为 2 个 Employee 对象是相等的,如果它们具有相同的employeeName. Set 不允许重复。但在这里我可以观察到一种奇怪的行为。这是我的代码。(我在这里没有使用 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);
    }
}

Here the output for the above code is,
[Name is: A Emp id is: 1, Name is: A Emp id is: 2, Name is: B Emp id is: 3]

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

My first question is, in equals() method, I consider 2 Employee objests to be equal if they have same employeeName but in compareTo method, I am using employeeId to sort. In this case, output is showing 2 entries for employeeName 'A'. How is TreeSet allowing a duplicate entry when I consider 2 objects to be same if they have the same employeeName. How is this possible..? And Second question is, in the compareTo method, if I use employeeName to sort, then I dont get the second repeated entry for the same name. The output in this second case is
[Name is: A Emp id is: 1, Name is: B Emp id is: 3]

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

Why is it so..?

为什么会这样..?

回答by Luiggi Mendoza

The problem is here:

问题在这里:

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

You must compare Strings using equalsmethod:

您必须String使用equals方法比较s :

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

Refer to How do I compare strings in Java?

请参阅如何比较 Java 中的字符串?

Also, since you're overriding equalsmethod, it would be good if you override hashCodemethod as well, as stated in Object#equalscontract:

此外,由于您要覆盖equals方法,因此如果您也覆盖hashCode方法,如Object#equals合同中所述,那将会很好:

Note that it is generally necessary to override the hashCode method whenever this method is overridden, so as to maintain the general contract for the hashCode method, which states that equal objects must have equal hash codes.

请注意,每当重写此方法时,通常都需要重写 hashCode 方法,以维护 hashCode 方法的一般约定,即相等的对象必须具有相等的哈希码。

Additional: Since you're using TreeSet, it will use the compareTomethod instead of the equalsand hashCodemethods. This is because TreeSetimplements SortedSetinterface. Refer to SortedSetjavadoc (emphasis mine):

附加:由于您使用的是TreeSet,它将使用compareTo方法而不是equalshashCode方法。这是因为TreeSet实现了SortedSet接口。参考SortedSetjavadoc(强调我的):

A Set that further provides a total ordering on its elements. The elements are ordered using their natural ordering(i.e. implementing Comparable<T>), or by a Comparatortypically provided at sorted set creation time.

进一步提供其元素的总排序的 Set。元素使用它们的自然排序(即实现Comparable<T>排序,或者通过Comparator通常在排序集创建时提供的排序。

You should implement this method in the accordingly to your needs:

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

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);
}

Since you're comparing Strings, I would recommend using StringUtilsclass from Apache Commons Langthat provides helper methods to avoid nullchecks and others.

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

回答by Onur A.

you should comparestringnot with ==, but with equals()method, and also you should override your compareTomethod to compare with employeeNamenot with employeeId, if you want it in that way.

您不应该与==进行比较,而是与方法进行比较,并且您还应该覆盖您的方法以与not进行比较,如果您希望以这种方式进行比较。stringequals()compareToemployeeNameemployeeId

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

and

public int compareTo(Employee emp) {

  return (this.employeeName-emp.employeeName);
}

回答by sanbhat

The way you are comparing string is wrong. See How to compare 2 Strings in Java

您比较字符串的方式是错误的。请参阅如何在 Java 中比较 2 个字符串

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

should be

应该

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