HashSet不删除现有元素 [英] HashSet not removing existing element
问题描述
我有一个Output类,它基本上包含一个BitSet,其hashCode和equals上具有覆盖值.然后,我有一个输出的HashSet,并且执行以下操作:
I have a class Output which basically contains a BitSet with overides on hashCode and equals. Then I have a HashSet of Outputs and I do the following operations :
Set<Output> outputs = new HashSet<>();
Output o1 = new Output();
o1.flip(3);
Output o2 = new Output();
o2.flip(1);
o2.flip(3);
outputs.add(o1);
outputs.add(o2);
如果我进行打印(输出),我会得到
If I do a print(outputs) I get
[Output@5a1, Output@5a3]
现在可以了
o2.flip(1);
我知道
[Output@5a3, Output@5a3]
这当然是Set的正常行为,因为Set无法意识到元素的哈希码已更改.
which of course, is the normal behavior of a Set, since the Set can't be aware that the hashcode of an element has changed.
如果我现在这样做
outputs.remove(o1);
我知道
[Output@5a3]
完美!
但是如果我再做一次
outputs.remove(o1); //or outputs.remove(o2);
它返回false
,我仍然有[Output@5a3]
这很奇怪,因为如果我这样做
And this is strange since if I do
outputs.contains(o1) -> false
这可能解释了删除行为,尽管我不理解为什么它会返回false,因为
which may explain the remove behavior, altough I don't understand why it returns false since if I do
for(Output o : outputs) {
System.out.println(o.equals(o1));
}
它输出true
.
为什么会发生这种情况?
Any ideas why this happens?
完整代码:
class Output {
BitSet values;
public Output() {
values = new BitSet(4);
}
public void flip(int index) {
values.flip(index);
}
public int hashCode() {
int hash = 3;
hash = 67 * hash + Objects.hashCode(this.values);
return hash;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Output)) {
return false;
}
Output other = (Output) obj;
return this.values.equals(other.values);
}
}
public class Main {
public static void main(String args[]) {
Set<Output> outputs = new HashSet<>();
Output o1 = new Output();
o1.flip(3);
Output o2 = new Output();
o2.flip(1);
o2.flip(3);
outputs.add(o1);
outputs.add(o2);
System.out.println(outputs);
o2.flip(1);
System.out.println(outputs);
outputs.remove(o1);
System.out.println(outputs);
outputs.remove(o1);
System.out.println(outputs);
for (Output o : outputs) {
System.out.println(o.equals(o1));
}
}
}
输出:
[Output@5a1, Output@5a3]
[Output@5a3, Output@5a3]
[Output@5a3]
[Output@5a3]
true
推荐答案
当您更改HashSet
的元素(或HashMap
中的键)时,该元素的hashCode
可能会更改(并且在在您的示例中,hashCode
取决于您更改的BitSet
成员的hashCode
).
When you mutate an element of a HashSet
(or a key in a HashMap
), the hashCode
of that element may change (and in your example, the hashCode
depends on the hashCode
of the BitSet
member, which you changed).
但是,HashSet
不知道该更改,因此不会将元素移动到与新hashCode
相对应的bin中.
However, the HashSet
is not aware of that change, and therefore doesn't move the element to the bin corresponding with the new hashCode
.
因此,当您搜索该元素时,将使用新的hashCode
进行搜索(HashSet
搜索始终以hashCode
开始-仅在找到包含所有具有该hashCode
元素的单元格之后,equals()
用于查找正确的元素),但失败,因为该元素仍位于与原始hashCode
匹配的bin中.
Therefore, when you search for that element, the search is performed using the new hashCode
(HashSet
search always begins with the hashCode
- only after finding the bin that contains all the elements having that hashCode
, equals()
is used to find the right element), and it fails, since the element is still located in the bin matching the original hashCode
.
这就是突变HashSet
的元素是个坏主意的原因.
That's the reason it is a bad idea to mutate elements of a HashSet
.
这篇关于HashSet不删除现有元素的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!