[英]As per TreeSet two objects are shown equal but Queue shows them as unequal
I have the follwing Person Class -我有以下 Person 类-
Person.java
- Person.java
-
public class Person implements Comparable<Person> {
private int id;
private String name;
Person(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "Person: Id = " + id + ", Name = " + name;
}
@Override
public int compareTo(Person person) {
int myReturn = 0;
int minLength = 0;
int i = 0;
boolean equal = false;
if (id > person.id) {
myReturn = 1;
} else if (id < person.id) {
myReturn = -1;
} else {
if (name.length() > person.name.length()) {
minLength = person.name.length();
} else if (name.length() < person.name.length()) {
minLength = name.length();
} else {
equal = true;
minLength = name.length();
}
for (i = 0; i < minLength; i++) {
if (name.charAt(i) > person.name.charAt(i)) {
myReturn = 1;
break;
} else if (name.charAt(i) < person.name.charAt(i)) {
myReturn = -1;
break;
} else {
continue;
}
}
if (i == minLength) {
if (equal) {
myReturn = 0;
} else if (name.length() > person.name.length()) {
myReturn = 1;
} else {
myReturn = -1;
}
}
}
return myReturn;
}
}
Now, I have the following TreeClass instance -现在,我有以下 TreeClass 实例 -
TreeSet<Person> treeSet = new TreeSet<>(List.of(
new Person(4, "Amrita"),
new Person(4, "Amrita"),
new Person(9, "Sunita"),
new Person(12, "Nisha"),
new Person(9, "Sunit"),
new Person(9, "Sunitaa")
));
Upon printing -打印时——
Person: Id = 4, Name = Amrita
Person: Id = 9, Name = Sunit
Person: Id = 9, Name = Sunita
Person: Id = 9, Name = Sunitaa
Person: Id = 12, Name = Nisha
So clearly, the two Person instances - new Person(4, "Amrita")
and new Person(4, "Amrita")
are equal.很明显,两个 Person 实例 -
new Person(4, "Amrita")
和new Person(4, "Amrita")
是相等的。
Now, I have the following Queue code.现在,我有以下队列代码。 Since, Queue is a subinterface of Collection interface it implements all methods of Collection interface.
由于 Queue 是 Collection 接口的子接口,它实现了 Collection 接口的所有方法。 So -
所以 -
Queue<Person> queue3 = new LinkedList<>(List.of(
new Person(4, "Amrita"),
new Person(2, "Suhana"),
new Person(7, "Neha")
));
Person person1 = new Person(4, "Amrita");
Person person2 = new Person(9, "Sunita");
System.out.println(queue3.contains(person1));
System.out.println(queue3.contains(person2));
Ouput -输出 -
false
false
Thus it says that new Person(4, "Amrita")
element of Queue and Object new Person(4, "Amrita")
are unequal.因此,它表示 Queue 的
new Person(4, "Amrita")
元素和 Object new Person(4, "Amrita")
不相等。
How is this possible?这怎么可能?
You need to override @equals
method in the class Person
.您需要覆盖
Person
类中的@equals
方法。 See documentation .请参阅文档。
Additionally I see that Person
implemented Comparable
(TreeSet uses compareTo
for equality).此外,我看到
Person
实现了Comparable
(TreeSet 使用compareTo
来表示相等)。 Whenever you @override
compareTo()
, it is highly recommended to @overide
@equals
.每当您
@override
compareTo()
时,强烈建议您使用@overide
@equals
。
From Collections Documentation :从集合文档:
It is strongly recommended (though not required) that natural orderings be consistent with equals.强烈建议(尽管不是必需的)自然排序与 equals 一致。 This is so because sorted sets (and sorted maps) without explicit comparators behave "strangely" when they are used with elements (or keys) whose natural ordering is inconsistent with equals.
之所以如此,是因为没有显式比较器的排序集(和排序映射)在与自然顺序与等于不一致的元素(或键)一起使用时表现“奇怪”。
To cut the long story short, since you are using TreeSet as well as other collections (List), you need to @override all three - compareTo, equals and hashCode
长话短说,由于您使用 TreeSet 以及其他集合(列表),您需要 @override 所有三个 -
compareTo, equals and hashCode
PS: Whenever you override @equals
- please @override
hashCode
too. PS:每当你覆盖
@equals
- 请@override
hashCode
。 See this .看到这个。
You can generate these methods inside IDE (Intellij / Eclipse/ VsCode etc) automatically.您可以在 IDE(Intellij/Eclipse/VsCode 等)中自动生成这些方法。 Eg it would be something like this:
例如,它会是这样的:
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return id == person.id && Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(id, name);
}
TreeSet
exclusively uses the comparator to determine equality. TreeSet
专门使用比较器来确定相等性。 Any 2 entries such that comparator.compare(a, b)
returns 0 are deemed equal. comparator.compare(a, b)
返回 0 的任何 2 个条目都被视为相等。 Neither equals
nor hashCode
are invoked at all.根本不调用
equals
和hashCode
。
Most other collections exclusively use either just equals
, or a combination of equals
and hashCode
to determine this.大多数其他集合仅使用
equals
或equals
和hashCode
的组合来确定这一点。
Thus, if you write a class whose equals, hashCode, and compare methods are in disagreement, you can create the situation you described: Where TreeSet considers them equal but eg HashSet does not.因此,如果您编写的类的 equals、hashCode 和 compare 方法不一致,您可以创建您所描述的情况:TreeSet 认为它们相等但例如 HashSet 不相等。
The solution is to properly apply the rules as laid out in the javadocs of the various java.util
classes:解决方案是正确应用各种
java.util
类的 javadocs 中列出的规则:
a.equals(b)
? a.equals(b)
? Then, b.equals(a)
must also hold, regardless of the types.b.equals(a)
也必须成立。a.equals(a)
must be true. a.equals(a)
必须为真。a.equals(anything)
cannot throw any exceptions, except the forced NPE if a
is null
. a.equals(anything)
不能抛出任何异常,除非a
为null
时强制 NPE。 Same for a.hashCode()
.a.hashCode()
相同。a.equals(null)
must be false. a.equals(null)
必须为假。a.equals(b)
and b.equals(c)
? a.equals(b)
和b.equals(c)
? Then a.equals(c)
must also be true.a.equals(c)
也必须为真。a.equals(b)
? a.equals(b)
? Then a.hashCode() == b.hashCode()
must also be true.a.hashCode() == b.hashCode()
也必须为真。 The reverse does not hold (equal hashcodes? That doesn't imply equal objects).a.compare(b)
is below 0? a.compare(b)
低于 0? Then b.compare(a)
must be above 0.b.compare(a)
必须大于 0。a.compare(a)
must be 0. a.compare(a)
必须为 0。a.compare(b) == 0
must match with a.equals(b)
If one is true the other must be true and vice versa. a.compare(b) == 0
必须与a.equals(b)
匹配,如果一个为真,则另一个必须为真,反之亦然。a.compare(b) < 0
and b.compare(c) < 0
? a.compare(b) < 0
和b.compare(c) < 0
? Then a.compare(c)
must also be below 0. Same for above 0.a.compare(c)
也必须低于 0。高于 0 也是如此。equals
and hashCode
, compare
is allowed to throw a number of exceptions.equals
和hashCode
不同, compare
允许抛出许多异常。 It's a lot of rules.这是很多规则。 They are easy to understand (bordering on the obvious), and yet they are quite hard to properly apply especially if you involve the idea that java has a type hierarchy.
它们很容易理解(几乎是显而易见的),但它们很难正确应用,尤其是当您涉及到 java 具有类型层次结构的想法时。
Trivial example:简单的例子:
ArrayList
has an equals impl that will check if the provided object is a list of any kind, and if it is, it'll just do an elem-by-elem comparison. ArrayList
有一个 equals impl,它将检查提供的对象是否是任何类型的列表,如果是,它将只进行逐个元素的比较。
This means you CANNOT write a class that implements List
and add equality-affecting properties of ANY sort, period .这意味着您不能编写实现
List
的类并添加任何排序的影响相等的属性 period 。
For example, this class:例如,这个类:
class ColouredList<T> extends ArrayList<T> {
private Color color;
public ColouredList(Color color) {
this.color = color;
}
// and so on
}
CANNOT BE WRITTEN - unless you disregard colour entirely, and eg an empty blue list is deemed equal to an empty red one.不能写——除非你完全不考虑颜色,例如一个空的蓝色列表被认为等于一个空的红色列表。 Because
emptyPlainArrayList.equals(blueEmptyList)
is true and you can't make that false (as you do not control the equals impl of ArrayList), and so is emptyPlainArrayList.equals(redEmptyList)
, therefore, blueEmptyList.equals(redEmptyList)
also has to be true.因为
emptyPlainArrayList.equals(blueEmptyList)
是真的,你不能把它设为假(因为你不控制 ArrayList 的 equals impl emptyPlainArrayList.equals(redEmptyList)
,emptyPlainArrayList.equals(redEmptyList) 也是如此,因此blueEmptyList.equals(redEmptyList)
也有是真实的。
This rule is a logical consequence of the ruleset, and yet, not obvious and in fact a somewhat common mistake to think you can do that.这条规则是规则集的逻辑结果,但并不明显,实际上认为你可以做到这一点是一个有点常见的错误。
Hence, easy, almost obvious rules that combine to make a system that is much more complex than you'd think.因此,简单的、几乎显而易见的规则结合起来形成了一个比你想象的要复杂得多的系统。
You violated one of the rules here;您违反了此处的一项规则; given what you pasted, seems like a simple one: You added a natural comparison order to your class but failed to implement hashCode and equals.
鉴于您粘贴的内容,看起来很简单:您向您的类添加了自然比较顺序,但未能实现 hashCode 和 equals。 You must implement these methods, in order to follow the rule that
a.equals(b)
and a.compare(b) == 0
have to hold (and you have to implement hashCode
to follow the rule "if a.equals(b)
then you have to ensure a.hashCode() == b.hashCode()
.您必须实现这些方法,以遵循
a.equals(b)
和a.compare(b) == 0
必须遵守的规则(并且您必须实现hashCode
以遵循规则“如果a.equals(b)
那么你必须确保a.hashCode() == b.hashCode()
。
I suggest Project Lombok or your IDE's "generate equals and hashcode" option.我建议Project Lombok或您的 IDE 的“生成等于和哈希码”选项。 These methods, too, can be a bit tricky to write properly.
这些方法也可能有点难以正确编写。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.