会发生什么,以查找一个HashMap的Hashset或物体Hashcode方法发生变化时(What

2019-07-03 12:04发布

在一个HashMap提供的密钥的散列码是用来放置在哈希表的值。 在一个HashSet的obects哈希码是用来放置的值在下面的哈希表。 即HashMap中的好处是,你必须确定你想要什么的关键,所以你可以做的好东西像这样的灵活性。

Map<String,Player> players = new HashMap<String,Player>();

这串映射,如玩家名字命名的播放器本身。

我的问题是是发生了什么,以查找时,关键的Hashcode方法的变化。

这一点,我希望不是因为我不希望,也不想让键来改变一个HashMap这样一个重大问题。 在前面的例子中,如果玩家名称的变化,他不再是那个球员。 但是我可以看看一个球员使用密匙变化等领域不属于名称和将来的查询会工作。

然而,由于整个对象的hashCode一个HashSet是用来放置物品,如果有人稍微改变了某一对象的未来查找将不再解析到Hashtable中相同的位置,因为它依赖于整个对象的哈希码。 这是否意味着,一旦数据是一个HashSet它不应该被改变。 或是否需要进行重新处理? 或者它会自动完成等? 到底是怎么回事?

Answer 1:

在您的例子中,字符串是不可变的如此的哈希码不能改变。 但假设,如果一个对象的哈希码确实改变了,而在哈希表中的关键字,那么它很可能就散列表查找担心消失 。 我走进更详细的在这个答案的相关问题: https://stackoverflow.com/a/13114376/139985 。 (原来的问题是关于一个HashSet ,但是HashSet确实是一个HashMap被窝里,所以答案也涵盖这种情况。)

它是安全地说,如果任何一个HashMap或映像树的钥匙,影响他们各自的方式突变hashcode() / equals(Object)compare(...)compareTo(...)的合同,然后数据结构将“打破”。


这是否意味着,一旦数据是一个HashSet它不应该被改变。

是。

或是否需要进行重新处理? 或者它会自动完成等?

它不会自动重新处理。 该HashMap不会注意到一个关键的哈希码已经改变。 事实上,你甚至不会得到哈希码的重新计算时HashMap调整大小。 该数据结构记住原始哈希码值,以避免重新计算所有的散列码的时哈希表调整大小。

如果你知道一个关键的哈希码都不会改变,你需要在你的变异关键删除从表中的条目,并将其添加回之后。 (如果您尝试remove / put它变异的关键后,很有可能的是, remove将无法找到入口。)

到底是怎么回事?

这是怎么回事是你违反了合同中清楚列明HashMap的javadoc。 不这样做!



Answer 2:

在您的例子,该键是字符串,是不可改变的。 所以按键的哈希码不会改变。 当的按键变化的哈希码是不确定的,并导致“怪异”的行为会发生什么。 请参见下面的实施例,打印1,假和2对象保持在所述一组,但该组看起来是断开(包含返回false)。

从提取设置的Javadoc :

注意:如果使用可变对象作为一组元素大,一定要小心。 如果一个对象的值以影响equals比较而对象是在该组的元素的方式改变一组的行为没有被指定。 这种禁止的特殊情况是,它是不允许的一组以自身作为一个元素。

public static void main(String args[]) {
    Set<MyObject> set = new HashSet<>();
    MyObject o1 = new MyObject(1);
    set.add(o1);
    o1.i = 2;
    System.out.println(set.size());       //1
    System.out.println(set.contains(o1)); //false
    for (MyObject o : set) {
        System.out.println(o.i);          //2
    }
}

private static class MyObject {
    private int i;

    public MyObject(int i) {
        this.i = i;
    }

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

    @Override
    public boolean equals(Object obj) {
        if (obj == null) return false;
        if (getClass() != obj.getClass()) return false;
        final MyObject other = (MyObject) obj;
        if (this.i != other.i) return false;
        return true;
    }
}


Answer 3:

随着Java的哈希值,原来的基准是根本无法找到。 它在搜索对应当前哈希码桶中,并没有发现。

这样的事实后从此一蹶不振,哈希的keySet必须遍历,和和不被发现的任何键contains必须通过迭代器中删除方法。 最好是从地图中删除键,然后存储与新键的值。



Answer 4:

HashSet是由备份HashMap

从的javadoc。

此类实现Set接口,由哈希表(实际上是一个HashMap实例)支持。

所以,如果你改变了哈希码,我怀疑你是否可以访问该对象。

内部实施细则

add的实现HashSet

 public boolean add(E e) {
        return map.put(e, PRESENT)==null;
 }

关键是ELEM和价值就被称为呈现虚拟对象

contains实施

public boolean contains(Object o) {
        return map.containsKey(o);
}


文章来源: What happens to the lookup in a Hashmap or Hashset when the objects Hashcode changes