内部对象更改时HashSet的哈希解决方法

时间:2012-01-10 15:31:21

标签: java collections hash set hashcode

这个SO的答案解释了我遇到的问题:HashSet.remove() and Iterator.remove() not working

基本上,一旦我向HashSet添加了一些内容,如果我修改了它的任何字段,那么该集将使用包含具有完全相同字段的对象的集合的任何相等性测试失败,因为它存储的哈希码是因为它设置了不同的字段。

所以,既然这个答案解释了正在发生什么,那么为什么这将是一个很好的解决方法,既具有使用集合的唯一性又能够修改集合中对象的内部字段?或者这是不可能的?

5 个答案:

答案 0 :(得分:7)

如果您修改的字段不是相等测试的一部分,则它们也不应该是哈希代码计算的一部分。在这种情况下,没有问题:您可以修改这些字段。

如果字段 是等式测试的一部分,那么最干净的方法可能是从集合中删除对象,然后修改并重新插入它。

如果是后者,并且您发现自己做了很多,那么您可能需要重新访问手头问题的数据结构选择。

答案 1 :(得分:6)

从集合中删除要修改的对象,进行更改,然后重新添加。据我所知,没有标准Set实现可以处理存储时更改的字段(在hashCode()compareTo()实现中使用)。

或者,如果字段不是用于确定身份,相等或位置(即未在hashCode()compareToequals()中使用),则没问题。

答案 2 :(得分:3)

解决它的唯一方法是不使用依赖于任何可变字段的hashCode()方法。如果对象具有独立于其字段值的标识和存在,那么这很容易 - 使用System.identityHashCode()。否则,您可以将hashCode()基于一个非可变字段。如果没有,那我恐怕你运气不好。

答案 3 :(得分:1)

使用HashMap而不是HashSet。将密钥定义为在时间上不会改变的独特内容。

答案 4 :(得分:-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;
    }
}