ArrayList<Integer> lis = new ArrayList<Integer>();
lis.add(2);
lis.add(3);
ArrayList<Integer> lis2 = new ArrayList<Integer>();
lis2.add(2);
lis2.add(3);
HashMap<ArrayList<Integer>, Integer> map = new HashMap<ArrayList<Integer>, Integer>();
map.put(lis, 7);
System.out.println(map.containsKey(lis2));
最初,我希望代码打印出'false',因为lis和lis2是不同的对象。 令人惊讶的是,代码打印出“真实”。 hashmap在调用containsKey()时检查什么?
答案 0 :(得分:7)
检查.hashCode
以查找存储桶,然后使用.equals
。如果所有元素的顺序相同且List.equals
为true
,则.equals
会返回ArrayList.hashCode
。 ArrayList
将为具有相同元素的两个.equals
实例返回相同的值,因此它找到正确的存储桶,然后使用ArrayList<Integer> lis = new ArrayList<Integer>();
lis.add(2);
lis.add(3);
ArrayList<Integer> lis2 = new ArrayList<Integer>();
lis2.add(2);
lis2.add(3);
System.out.println(lis.equals(lis2)); // Prints "true"
并看到列表的元素是相同的并且在同样的顺序。
例如:
HashMap
值得注意的是,永远不会使用可变对象作为map.put(lis, 7);
lis.add(3);
System.out.println(map.get(lis)); // Prints "null", *not* "7"
中的密钥。通过修改密钥,可以使其所在的存储桶无效。例如,如果我这样做:
lis.hashCode()
这是因为添加另一个元素会更改put
的值。当您hashCode
列表时,map.put(lis, 7);
lis.add(3);
map.put(lis, 7);
System.out.println(map.size()); // Prints "2"
用于挑选广告资源。通过添加新元素,您可以更改它将使用的存储桶,但不会更改已添加到地图中的条目的存储桶。添加到上面:
Collections.unmodifiableList
它第二次解析为另一个桶,因此它将其视为第二个元素。
在这种情况下,您可以使用map.put(Collections.unmodifiableList(lis), 7);
来“冻结”列表,添加它,然后再不再触摸它:
get().add(3)
然后,如果您致电map.get(7).add(3);
:
UnsupportedOperationException
这将抛出{{1}}。
答案 1 :(得分:3)
这是因为lis和lis2的 hashCode 相等。
lis2.hashCode()== lis.hashCode()为真。
源代码中的方法 containsKey (HashMap)如下:
/**
* Returns <tt>true</tt> if this map contains a mapping for the
* specified key.
*
* @param key The key whose presence in this map is to be tested
* @return <tt>true</tt> if this map contains a mapping for the specified
* key.
*/
public boolean containsKey(Object key) {
Object k = maskNull(key);
int hash = hash(k.hashCode());
int i = indexFor(hash, table.length);
Entry e = table[i];
while (e != null) {
if (e.hash == hash && eq(k, e.key))
return true;
e = e.next;
}
return false;
}
答案 2 :(得分:1)
您将哈希映射定义为
HashMap<ArrayList<Integer>, Integer> map = new HashMap<ArrayList<Integer>, Integer>();
所以键是一个整数列表,值是一个整数。
map.containsKey(lis2)会尝试查找给定密钥的匹配项。因此,将在每个键上调用 equals 方法。由于该键实际上是一个整数列表,因此将按顺序对该列表的每个项调用equal方法。
这就是输出为真的原因。
如果更改第二个列表中的任何项目甚至是项目的顺序,则输出将为false。
答案 3 :(得分:1)
map.containsKey
将返回true
。它使用equals
的{{1}}方法来检查相等性:
key
如果(从ArrayList doc复制),两个arraylists被认为是相等的:
将指定对象与此列表进行比较以获得相等性。返回 当且仅当指定的对象也是列表时才为true,两个列表都是如此 具有相同的大小,以及两者中所有相应的元素对 清单是平等的。 (如果(e1 == null,两个元素e1和e2相等)? e2 == null:e1.equals(e2))。)换句话说,定义了两个列表 如果它们包含相同顺序的相同元素,则相等。
此实现首先检查指定的对象是否为此列表。 如果是,则返回true;如果没有,它会检查指定的对象是否为a 名单。如果不是,则返回false;如果是这样,它会遍历两个列表, 比较相应的元素对。如果任何比较返回 false,此方法返回false。如果任何迭代器耗尽 另一个元素返回false(如列表所示) 不等长);否则它在迭代时返回true 完整。
由于这两个列表包含相同数量的元素,因此它们被视为key != null && key.equals(k)
,这就是equal
返回map.containsKey(lis2)
的原因。