当将键值对添加到哈希映射中时,为什么Java会使哈希映射的哈希码更改? [英] when add key-value pair to a hashMap, why Java makes hashMap's hashCode change?

查看:119
本文介绍了当将键值对添加到哈希映射中时,为什么Java会使哈希映射的哈希码更改?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果您查看hashMap中java的hashCode方法,您会发现:
$ b $ pre $ public int hashCode(){
int h = 0;
Iterator< Entry< K,V>> i = entrySet()。iterator();
while(i.hasNext())
h + = i.next()。hashCode();
返回h;





$ b

因此,当你在hashMap中插入东西时,hashMap的hashCode会改变。因此,如果我们在hashSet中插入一个空的hashMap,然后在这个hashMap中插入一些东西,然后调用 hashSet.contains(hashMap),它将返回 false
为什么Java允许这样的行为?这很容易导致hashSet中的重复项目。



尝试运行以下代码:

  import java.util.HashMap; 
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;

public class Main {

public static void main(String [] args){

HashSet< HashMap< Integer,String>> set = new HashSet<>();
HashMap< Integer,String> b = new HashMap<>();
System.out.println(adding hashcode:+ b.hashCode()+to set);
set.add(b);
b.put(8,阿森纳);
for(HashMap< Integer,String> map:set){
Iterator it = map.entrySet()。iterator(); (it.hasNext()){
Map.Entry pair =(Map.Entry)it.next();
System.out.println(pair.getKey()+=+ pair.getValue());


System.out.println(Finding b:+ set.contains(b));
System.out.println(b.hashCode());

set.add(b);

(HashMap< Integer,String> map:set){
Iterator it = map.entrySet()。iterator(); (it.hasNext()){
Map.Entry pair =(Map.Entry)it.next();
System.out.println(pair.getKey()+=+ pair.getValue());






$ div class =为什么Java允许这样的行为?

因为Java允许这样的行为根据它们的 equals()实现,键应该是不变的。如果你改变一个键的方式,通过它的 equals()方法进行比较会受到影响,那么这个表的行为是不确定的。



这正是您在更改 HashMap 时所做的,而它是 HashSet ,因为 HashSet 实际上由 HashMap 支持。



这是的摘录 Map 界面文档
$ b


注意:必须非常小心如果可变对象用作映射键。如果对象的值以影响等于比较的方式更改,而对象是地图中的关键字,则不会指定地图的行为。这种禁令的一个特例是,地图不允许自己作为关键字。虽然允许地图将自身包含为值,但建议您格外小心:equals和hashCode方法在这样的地图上不再有效。


如果我是你,我不会使用可变映射作为依赖于其元素不变性的结构的关键。


If you look at java's hashCode method inside hashMap, you will find:

public int hashCode() {
    int h = 0;
    Iterator<Entry<K,V>> i = entrySet().iterator();
    while (i.hasNext())
        h += i.next().hashCode();
    return h;
}

So when you insert things into hashMap, hashMap's hashCode will change. Thus, if we insert an empty hashMap into hashSet, then insert something to this hashMap, then call hashSet.contains(hashMap), it will return false. Why does Java allow such behavior? This will easily cause duplicate items in a hashSet.

Try run the following code:

import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;

public class Main {

    public static void main(String[] args) {

        HashSet<HashMap<Integer, String>> set = new HashSet<>();
        HashMap<Integer, String> b = new HashMap<>();
        System.out.println("adding hashcode: " + b.hashCode() + "to set");
        set.add(b);
        b.put(8, "arsenal");
        for(HashMap<Integer, String> map: set){
            Iterator it = map.entrySet().iterator();
            while (it.hasNext()) {
                Map.Entry pair = (Map.Entry)it.next();
                System.out.println(pair.getKey() + " = " + pair.getValue());
            }
        }
        System.out.println("Finding b: " + set.contains(b));
        System.out.println(b.hashCode());

        set.add(b);

        for(HashMap<Integer, String> map: set){
            Iterator it = map.entrySet().iterator();
            while (it.hasNext()) {
                Map.Entry pair = (Map.Entry)it.next();
                System.out.println(pair.getKey() + " = " + pair.getValue());
            }
        }

    }
}

解决方案

Why Java allow such behavior?

Because keys are supposed to be invariant, according to their equals() implementation. If you mutate a key in such a way that comparisons by means of its equals() method are affected, then the behaviour of the map is unspecified.

And this is exactly what you're doing when you change your HashMap while it's an element of the HashSet, since HashSet is actually backed by a HashMap.

This is an excerpt of the Map interface documentation:

Note: great care must be exercised if mutable objects are used as map keys. The behavior of a map is not specified if the value of an object is changed in a manner that affects equals comparisons while the object is a key in the map. A special case of this prohibition is that it is not permissible for a map to contain itself as a key. While it is permissible for a map to contain itself as a value, extreme caution is advised: the equals and hashCode methods are no longer well defined on such a map.

If I were you, I wouldn't use a mutable map as the key of a structure that relies on the immutability of its elements.

这篇关于当将键值对添加到哈希映射中时,为什么Java会使哈希映射的哈希码更改?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆