在 HashMap 中多次使用键时无限循环

Infinite loop when using a key multiple times in HashMap

HashMap陷入死循环

我无法理解为什么 HashMap 在多次使用同一个密钥时会抛出 Whosebug 错误。

代码:

import java.util.HashMap;

public class Test {
    public static void main(String[] args) {
        HashMap hm = new HashMap();

        hm.put(hm, "1");
        hm.put(hm, "2");
    }
} 

错误:

Exception in thread "main" java.lang.WhosebugError

你使用 hashmap 本身作为键 -> 这意味着递归 -> 没有退出条件 -> Whosebug。

只需使用一个键(Long、String、Object 任何你想要的)。

是的,正如 Seek Addo 所建议的那样,添加带有 <> 括号的类型。

无法将 Map 本身作为密钥添加。来自 javadoc:

A special case of this prohibition is that it is not permissible for a map to contain itself as a key.


问题是您使用的键不是标准对象(具有明确定义的 equalshashCode 方法的任何对象,不是地图本身),而是地图本身。

问题在于 HashMaphashCode 是如何计算的:

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

如您所见,为了计算地图的哈希码,它遍历了地图的所有元素。对于每个元素,它计算 hashCode。因为映射的唯一元素是映射本身,所以它成为递归的来源。

将地图替换为另一个可用作键的对象(定义明确的 equalshashCode)将起作用:

import java.util.HashMap;

 public class Test {
   public static void main(String[] args) {
     HashMap hm = new HashMap();

     String key = "k1";
     hm.put(key, "1");
     hm.put(key, "2");
   }
} 

为了在 HashMap 中找到一个键(每当您调用 putgetcontainsKey 时就完成),hashCode 方法被称为钥匙。

对于HashMaphashCode()Map的所有条目的hashCode()的函数,而每个条目的hashCode是一个函数键和值的 hashCodes。由于您的密钥是相同的 HashMap 实例,因此计算该密钥的 hashCode 会导致 hashCode 方法调用的无限递归,从而导致 WhosebugError.

使用 HashMap 作为 HashMap 的键是个坏主意。

问题不在于哈希映射因 "same key" 输入两次而炸毁堆栈,而是因为您对映射键的特定选择。您正在向自身添加哈希映射。

为了更好地解释 - Map 契约的一部分是键不得以影响其 equals(或 hashCode)方法的方式改变。

当您将 map 作为键添加到自身时,您更改了键(map),使其 return 与您首次添加 map 时的 hashCode 不同。

更多信息来自 JDK 地图界面停靠点:

Note: great care must be exercised if mutable objects are used as map keys. The behavior of a map is not specified if the value of an object is changed in a manner that affects equals comparisons while the object is a key in the map. A special case of this prohibition is that it is not permissible for a map to contain itself as a key. While it is permissible for a map to contain itself as a value, extreme caution is advised: the equals and hashCode methods are no longer well defined on such a map.

您正在使用相同的对象名称作为键,因此它是无限循环。

所以是栈溢出。