为什么 ArrayList 作为 HashMap 中的键不起作用? [英] why doesn't ArrayList as key in HashMap work?

查看:23
本文介绍了为什么 ArrayList 作为 HashMap 中的键不起作用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 ArrayList 作为 HashMap 中的键,但是如果我在将列表设置为键后向列表添加值,则映射获胜不再识别列表.我已经为我的问题找到了解决方案,但这是一种丑陋的方法,以下是该问题的一些示例代码:

I am trying to use an ArrayList as a key in a HashMap, but if I add values to the list after setting the list as a key, the map won't recognize the list anymore. I have already found a solution for my problem, but it is an ugly way of doing it, here is some example code for the problem:

HashMap<Object,String> hm = new HashMap<Object,String>();

List<String> l = new ArrayList<String>();
hm.put(l, "stuff");
l.add("test");//add item after adding the list to the hashmap

System.out.println(hm.get(l));

这将返回文本null"而

this will return the text "null" while

HashMap<Object,String> hm = new HashMap<Object,String>();

List<String> l = new ArrayList<String>();
l.add("test"); //add item before adding the list to the hashmap
hm.put(l, "stuff");

System.out.println(hm.get(l));

工作正常并返回东西"

有人知道为什么会这样吗?

Does anyone know why this happens?

推荐答案

简短:因为键必须是不可变的,哈希映射才能工作(至少它们的身份必须是不可变的),而列表不是.

Short: because keys must be immutable for hashmaps to work (at least their identity must be immutable) and lists aren't.

Long:当您向映射添加键时,其 hashCode() 方法用于确定条目放入的存储桶.在该存储桶中 equals() 用于检查该键是否已存在于其中.查找也是如此.

Long: when you add a key to a map its hashCode() method is used to determine the bucket the entry is put into. Inside that bucket equals() is used to check whether that key already exists in there. The same is true for lookups.

现在 ArrayList 做了一个很深的 equals()hashCode() 所以如果你改变列表 after使用它作为键,你最终会在不同的桶中或者 equals() 得到不同的结果,并且地图很可能找不到它.

Now ArrayList does a deep equals() and hashCode() so if you alter the list after using it as key you'll end up in a different bucket or with a different outcome for equals() and the map most likely won't find it.

编辑

hashCode() 实现 AbstractList(由 ArrayList 扩展):

hashCode() implementation for AbstractList (which ArrayList extends):

public int hashCode() {
    int hashCode = 1;
    for (E e : this)
        hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());
    return hashCode;
}

如您所见:如果列表为空,则哈希码将为 1,否则哈希码将为其他内容(在您的情况下为 31 * "test".hashCode()).因此,您很可能最终会在另一个会失败的存储桶中查找.

As you can see: if the list is empty the hash code will be 1 otherwise the hash code will be something else (in your case 31 * "test".hashCode()). Thus you're likely to end up looking in a different bucket which will fail.

编辑 2

澄清equals() 的不同结果":当然 equals() 应该返回 true 如果用作键的列表和用于查找的列表包含相同顺序的相同元素.但是,如果您在将其用作键后更改该列表,您可能会遇到不同的情况:

Clarification on "different outcome for equals()": of course equals() should return true if the list used as a key and the list used for the lookup only contain equal elements in the same order. But if you change that list after using it as a key you might end up in different situations:

  • 虽然 hashCode 返回不同的值,但它可能会映射到同一个桶(在最坏的情况下,只考虑映射中的一个桶).在这种情况下,您最终会在列表中得到两个相等的键,尽管它们之前并不相等.
  • 您可能不知道列表的更改,因此即使您认为自己知道,也可能不会使用相等列表进行查找.

这篇关于为什么 ArrayList 作为 HashMap 中的键不起作用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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