我正在尝试使用ArrayList
作为HashMap
中的键,但是如果我在将列表设置为键后将值添加到列表中,则地图将不再识别列表。我已经为我的问题找到了一个解决方案,但这是一种丑陋的方式,这里有一些问题的示例代码:
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”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));
工作正常并返回“东西”
有谁知道为什么会这样?
答案 0 :(得分:7)
简短:因为密钥必须是不可变的才能使哈希图工作(至少它们的身份必须是不可变的)并且列表不是。
Long:当您向地图添加密钥时,其hashCode()
方法用于确定条目所放入的存储区。在该存储桶equals()
内部用于检查该密钥是否已存在于其中。查找也是如此。
现在ArrayList
执行深equals()
和hashCode()
因此,如果您在之后使用它作为键更改列表,您将最终进入不同的存储桶或equals()
的不同结果,地图很可能无法找到它。
修改强>
hashCode()
(AbstractList
延伸)的 ArrayList
实施:
public int hashCode() {
int hashCode = 1;
for (E e : this)
hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());
return hashCode;
}
如您所见:如果列表为空,则哈希码将为1,否则哈希码将是其他内容(在您的情况下为31 * "test".hashCode()
)。因此,您可能最终会在另一个失败的桶中寻找。
修改2
澄清&#34; equals()
&#34;的不同结果:当然equals()
如果用作键的列表和用于查找的列表,则应返回true 包含相同顺序的相同元素。但是如果在将其用作关键字后更改该列表,则可能会在不同的情况下结束: