当HashSet内部对象发生更改时,哈希HashSet的解决方法

8
这个SO中的答案解释了我的问题:HashSet.remove()和Iterator.remove()不起作用

基本上,一旦我将某物添加到HashSet中,如果修改其任何字段,则该集合将无法通过包含具有完全相同字段的对象的集合进行任何等式测试,因为它存储的哈希代码是在具有不同字段设置时使用的。
那么,由于该答案解释了正在发生的事情,有什么好的解决方法可以同时具有使用集合的独特性和能够修改集合中对象的内部字段?还是说这根本不可能?
5个回答

8
如果您修改的字段不是相等测试的一部分,那么它们也不应该是哈希码计算的一部分。在这种情况下,没有问题:您可以直接修改这些字段。
如果这些字段是相等测试的一部分,最清晰的方法可能是从集合中删除对象,然后修改并重新插入它。
如果是后者,并且您发现自己经常这样做,您可能需要重新考虑所面临问题的数据结构的选择。

7
从集合中删除要修改的对象,对其进行更改,然后再将其添加回去。据我所知,没有标准的Set实现可以处理在存储期间字段(用于hashCode()或compareTo()实现)被更改的情况。
或者,如果字段不用于确定身份、相等性或位置(即未在hashCode()、compareTo或equals()中使用),则没有问题。

选择您的答案,尽管它的投票数与aix基本相同,并且它比aix早几秒钟 :) 谢谢。我想我可能会重新评估在这种情况下使用Set。 - AHungerArtist

3

唯一的解决方法是不要让hashCode()方法依赖于任何可变字段。如果对象具有独立于其字段值的标识和存在,则这很容易 - 使用System.identityHashCode()。否则,您可以基于一个单一的非可变字段来确定hashCode()。如果没有这样的字段,那么恐怕你就没办法了。


1
使用HashMap代替HashSet。将键定义为在时间上不会改变的唯一值。

-1

使用任何其他集合(例如LinkedList),并仅在添加时检查唯一性,就像这样:

public class MySetList<E> extends LinkedList<E> implements Set<E> {
    private static final long serialVersionUID = 1L;

    @Override
    public boolean add(E e) {
        return new HashSet<E>(this).add(e) ? super.add(e) : false;
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接