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
I am able to insert duplicate entries in TreeSet. How to overcome this
提问by Prasad
I have a class called Employee which has employeeName
and employeeId
as its member variables.I am creating new Employee objects and then adding it into a TreeSet
where 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 的类,它具有employeeName
和employeeId
作为其成员变量。我正在创建新的 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 String
s using equals
method:
您必须String
使用equals
方法比较s :
((Employee)emp).employeeName.equals(this.employeeName)
Refer to How do I compare strings in Java?
Also, since you're overriding equals
method, it would be good if you override hashCode
method as well, as stated in Object#equals
contract:
此外,由于您要覆盖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 compareTo
method instead of the equals
and hashCode
methods. This is because TreeSet
implements SortedSet
interface. Refer to SortedSet
javadoc (emphasis mine):
附加:由于您使用的是TreeSet
,它将使用compareTo
方法而不是equals
和hashCode
方法。这是因为TreeSet
实现了SortedSet
接口。参考SortedSet
javadoc(强调我的):
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 aComparator
typically 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 StringUtils
class from Apache Commons Langthat provides helper methods to avoid null
checks and others.
由于您正在比较字符串,我建议使用Apache Commons Lang中的StringUtils
类,该类提供帮助方法来避免检查和其他方法。null
回答by Onur A.
you should comparestring
not with ==, but with equals()
method, and also you should override your compareTo
method to compare with employeeName
not with employeeId
, if you want it in that way.
您不应该与==进行比较,而是与方法进行比较,并且您还应该覆盖您的方法以与not进行比较,如果您希望以这种方式进行比较。string
equals()
compareTo
employeeName
employeeId
(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)