HashSet不删除现有元素 [英] HashSet not removing existing element

查看:125
本文介绍了HashSet不删除现有元素的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆