当前位置: 首页 > 知识库问答 >
问题:

当向hashMap添加键值对时,为什么Java会更改hashMap的hashCode?

滑骞尧
2023-03-14

如果你看看hashMap里面java的hashCode方法,你会发现:

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

因此,当您将内容插入哈希映射时,哈希映射的哈希代码将更改。因此,如果我们在哈希集中插入一个空的哈希映射,然后向此哈希映射插入一些内容,然后调用 hashSet.contains(哈希映射),它将返回 false。为什么 Java 允许这样的行为?这很容易导致哈希集中出现重复的项目。

请尝试运行以下代码

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());
            }
        }

    }
}

共有2个答案

郑宇
2023-03-14

鸽子洞原理保证可能会有碰撞。还有其他的< code>Map实现,包括< code>LinkedHashMap和< code>TreeMap,它们不显示您所描述的行为。在< code>LinkedHashMap的情况下,它在Javadoc(部分)中被描述为< code>Map接口的哈希表和链表实现,具有可预测的迭代顺序。

衡子安
2023-03-14

为什么Java允许这样的行为?

因为键应该是不变的,根据它们的equals()实现。如果您以影响通过其equals()方法进行比较的方式更改键,那么映射的行为是未指定的。

这正是当您在< code>HashMap是< code>HashSet的一个元素时所做的事情,因为< code>HashSet实际上是由< code>HashMap支持的。

这是< code>Map界面文档的摘录:

注意:如果可变对象被用作映射键,必须非常小心。当对象是映射中的键时,如果对象的值以影响等于比较的方式更改,则不指定映射的行为。这种禁止的一个特例是不允许地图将自身包含为一个键。虽然允许映射将自身包含为一个值,但还是要特别小心:equals和hashCode方法在这样的映射中已经没有很好的定义了。

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

 类似资料:
  • 因此,我有一个hashmap ,它存储每个字符串的arraylist。但是当我用ArrayList的新值添加另一对时,其他键值将被替换。因此,不同键的所有值都是相同的。 添加的第一个键: 对于第二个键,列表中有不同。但是,当添加第二个键(在put()方法之后)时,第一个键的值已经被替换。

  • 问题内容: 这是一个简单的问题,我有一个简单的HashMap,我想将其反转键和值。 我想创建一个新的HashMap,在其中放置相反的内容。 问题答案: 它们都是独一无二的,是的 如果您确定自己的值是唯一的,则可以遍历旧地图的条目。 另外,您可以使用Guava提供的双向地图,并使用方法: 随着java-8的发布,您也可以通过以下方式进行操作: 最后,我将我的贡献添加到了质子包装库中,该库包含Stre

  • 问题内容: 如果我创建一个新的HashMap和一个新的List,然后使用一些任意键将List放置在Hashmap中,然后再调用会影响我放置在HashMap中的内容吗? 更深层的问题是:当我向HashMap中添加某些内容时,是复制并放置了一个新对象,还是放置了对原始对象的引用? 谢谢! 问题答案: 这里发生的事情是您在哈希图中放置了 指向 列表的 指针 ,而不是列表本身。 当您定义 您正在定义指向列

  • 初学者问题:我有一个hashmap,它将整数数组存储为值。每个值的键是一个由两个整数(坐标)组成的对象。 我的问题是:如何根据对象中的两个坐标(我的“键”)从hashmap检索值? 我的协和类(在Eclipse的一点帮助下): 构建Hashmap: 如果我想访问坐标12,13上的数组,如何检索它?是否需要迭代(我希望不是,我想添加100000个坐标,当然要快速访问)。 我希望这能在某种程度上符合

  • 我跟踪过这个帖子 用tableview绑定hashmap(JavaFX) 并创建了一个由HashMap中的数据填充的TableView。 通过从创建并将该传递给的构造函数,从称为的接收其数据。(代码如下) 但是,尽管它是一个,带有,但当对基础HashMap进行更改时,TableView不会更新。 下面是我的代码: 这正是将hashmap与tableview(JavaFX)绑定的代码,只是我添加了以

  • 问题内容: 嗨,我有一个csv叫做。我试图逐行读取csv并将值转换为哈希键值对。这是代码:- csv文件如下:- 当我运行此代码时,出现此错误:- 谁能帮助我修复代码并找出程序中的错误? 问题答案: 在字符串中,当你把它分解的第一次只包含如没有在这样就会导致异常 如果不需要1,2等。可以查看以下代码: