在 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.
问题是您使用的键不是标准对象(具有明确定义的 equals
和 hashCode
方法的任何对象,不是地图本身),而是地图本身。
问题在于 HashMap
的 hashCode
是如何计算的:
public int hashCode() {
int h = 0;
Iterator<Entry<K,V>> i = entrySet().iterator();
while (i.hasNext())
h += i.next().hashCode();
return h;
}
如您所见,为了计算地图的哈希码,它遍历了地图的所有元素。对于每个元素,它计算 hashCode。因为映射的唯一元素是映射本身,所以它成为递归的来源。
将地图替换为另一个可用作键的对象(定义明确的 equals
和 hashCode
)将起作用:
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
中找到一个键(每当您调用 put
或 get
或 containsKey
时就完成),hashCode
方法被称为钥匙。
对于HashMap
,hashCode()
是Map
的所有条目的hashCode()
的函数,而每个条目的hashCode
是一个函数键和值的 hashCode
s。由于您的密钥是相同的 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.
您正在使用相同的对象名称作为键,因此它是无限循环。
所以是栈溢出。
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.
问题是您使用的键不是标准对象(具有明确定义的 equals
和 hashCode
方法的任何对象,不是地图本身),而是地图本身。
问题在于 HashMap
的 hashCode
是如何计算的:
public int hashCode() {
int h = 0;
Iterator<Entry<K,V>> i = entrySet().iterator();
while (i.hasNext())
h += i.next().hashCode();
return h;
}
如您所见,为了计算地图的哈希码,它遍历了地图的所有元素。对于每个元素,它计算 hashCode。因为映射的唯一元素是映射本身,所以它成为递归的来源。
将地图替换为另一个可用作键的对象(定义明确的 equals
和 hashCode
)将起作用:
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
中找到一个键(每当您调用 put
或 get
或 containsKey
时就完成),hashCode
方法被称为钥匙。
对于HashMap
,hashCode()
是Map
的所有条目的hashCode()
的函数,而每个条目的hashCode
是一个函数键和值的 hashCode
s。由于您的密钥是相同的 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.
您正在使用相同的对象名称作为键,因此它是无限循环。
所以是栈溢出。