6

我刚刚做了以下代码:

import java.util.HashSet;
import java.util.Set;


public class MyClass {

    private static class MyObject {
        private int field;

        public int getField() {
            return field;
        }

        public void setField(int aField) {
            field = aField;
        }

        @Override
        public boolean equals(Object other) {
            boolean result = false;
            if (other != null && other instanceof MyObject) {
                MyObject that = (MyObject) other;
                result = (this.getField() == that.getField());
            }
            return result;
        }

        @Override
        public int hashCode() {
            return field;
        }
    }

    public static void main(String[] args) {
        Set<MyObject> mySet = new HashSet<MyObject>();
        MyObject object = new MyObject();
        object.setField(3);
        mySet.add(object);
        object.setField(5);
        System.out.println(mySet.contains(object));
        MyObject firstElement = mySet.iterator().next();
        System.out.println("The set object: " + firstElement + " the object itself: " + object);
    }

}

它打印:

false
The set object: MyClass$MyObject@5 the object itself: MyClass$MyObject@5

基本上意味着object不被认为在集合中,而它的实例本身显然在集合中。这意味着如果我在集合中插入一个对象,然后更改参与方法计算的字段的值hashCode,那么该HashSet方法将按预期工作。这不是可能的错误的太大来源吗?有人如何为此类案件辩护?

4

3 回答 3

4

以下是 Set API 的引用。它解释了一切。

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

http://docs.oracle.com/javase/7/docs/api/java/util/Set.html

于 2013-10-25T12:50:01.313 回答
2

HashSet实施于HashMap

HashMap缓存 的hashCodekey因此如果您更改 ,hashCode即使哈希函数将 映射hashCode到与存在的原始对象相同的存储桶,但它不会找到,因为在检查对象相等性之前它会检查hashCode.

看到这一行:

if (e.hash == hash && ((k = e.key) == key || key.equals(k)))

如果hashCode通过哈希函数映射到不同的桶而不是原始对象,那么显然它找不到。

因此,即使更改 hashCode hashSet 也找不到相同的对象。希望能帮助到你。

因此 HashMap 或您放入 HashSet 的对象的键应该是不可变的或有效的不可变的。

@fazomisiek

public HashSet() {
       map = new HashMap<E,Object>();
   }

同样,如果您检查 HashSet 的来源,您可以找到它。

于 2013-10-25T12:52:15.493 回答
0

这个问题只是实现java.util.HashSet和底层的限制java.util.HashMap。从根本上说,您正在权衡修改集合中的元素以获得更快的插入/查找性能的能力——这只是使用哈希集/映射数据结构的合同的一部分。

如果你不能保证每个人都会记住他们不能修改集合中的对象,那么绝对防止这种情况发生的唯一方法是首先只将不可变对象插入集合中。

于 2013-10-25T12:52:40.813 回答