hashmap在调用containsKey()时检查什么?

时间:2013-10-29 07:17:33

标签: java hashmap hashtable containskey

    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()时检查什么?

4 个答案:

答案 0 :(得分:7)

检查.hashCode以查找存储桶,然后使用.equals。如果所有元素的顺序相同且List.equalstrue,则.equals会返回ArrayList.hashCodeArrayList将为具有相同元素的两个.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)的原因。