3

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

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。

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

你怎么看?

4

1 回答 1

3

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

Set Javadoc

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

于 2013-05-06T16:26:35.633 回答