【问题标题】:Changing the elements in a set changes the 'equals' semantics更改集合中的元素会更改“等于”语义
【发布时间】:2013-05-06 16:24:45
【问题描述】:

想象一下我们有这段代码。

public class HashAddAfter {
    private class A {
        public int value;
        public A(int value) {
            this.value = value;
        }
        public void setValue(int value) {
            this.value = value;
        }
        // Code for hashCode()...
        // Code for equals()...
    }

    Set<A> list1 = new HashSet<A>();
    Set<A> list2 = new HashSet<A>();

    public static void main(String[] args) {
        HashAddAfter x = new HashAddAfter();

        A e1 = x.new A(1);
        A e2 = x.new A(1);

        x.list1.add(e1);
        x.list2.add(e2);

        System.out.println(x.list1.equals(x.list2));   // true

        e1.setValue(4);
        e2.setValue(4);

        System.out.println(x.list1.equals(x.list2));   // false
    }
}

hashCode() 和 equals() 的代码由于篇幅限制,我没有放,但它是从 Eclipse 生成的。

问题是在改变两个集合中的元素之前,集合是相等的。更改它们的值(每个值都相同)后,集合不再相等,尽管 e1.hashCode() == e2.hashCode() 和 e1.equals(e2)。

我猜在比较两个 HashSet 时,Java 使用元素的原始 hashCode(插入时的那个)。因此,插入后更改元素会更改其原始 hashCode,因此 contains() 将返回 false。

在我看来,这是一种非常不直观的行为。

你怎么看?

【问题讨论】:

    标签: java equals hashset


    【解决方案1】:

    这正是预期的行为。 Set 实现不可能知道元素的 hashCode 已更改,因此它无法防御这种可能性。

    来自SetJavadoc

    注意:如果将可变对象用作集合元素,则必须非常小心。如果对象的值以影响等于比较的方式更改,而对象是集合中的一个元素,则不指定集合的​​行为。这种禁止的一个特殊情况是不允许集合包含自己作为元素。

    【讨论】:

      猜你喜欢
      • 2012-03-24
      • 1970-01-01
      • 1970-01-01
      • 2018-06-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多