HashMap
进入无限循环
我不能理解为什么HashMap
抛出stackoverflow错误时,相同的键被多次使用。
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");
}
}
错误:线程"main"异常java.lang.StackOverflowError
不能将Map
本身添加为键。从javadoc:
这个禁止的一个特殊情况是不允许map包含自身作为键。
问题是您使用的键不是标准对象(任何具有良好定义的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,它遍历映射的所有元素。对于每个元素,它计算hashCode。因为映射中唯一具有键的元素是映射本身,所以它成为递归的来源。
将map替换为另一个可以用作key的对象(具有良好定义的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");
}
}
问题不在于哈希映射会因为两次输入"相同的键"而破坏堆栈,而是因为您选择了特定的映射键。将哈希映射添加到自身。
为了更好地解释- Map契约的一部分是键不能以影响其equals(或hashCode)方法的方式更改。
当您将map添加到自身作为键时,您以一种方式更改了key (map),使其返回与首次添加map时不同的hashCode。
关于更多信息,这是来自JDK dock的Map接口:
注意:如果使用可变对象作为映射键,必须非常小心。如果对象的值以影响相等比较的方式更改,而该对象是映射中的键,则不指定映射的行为。这种禁止的一个特殊情况是,不允许map将自身包含为键。虽然允许map将自身包含为一个值,但建议非常小心:equals和hashCode方法不再在这样的map上定义良好。
为了在HashMap
中找到一个键(这是在调用put
或get
或containsKey
时完成的),为该键调用hashCode
方法。
对于HashMap
, hashCode()
是Map
所有条目的hashCode()
的函数,每个条目的hashCode
是键和值的hashCode
的函数。由于您的密钥是同一个HashMap
实例,计算该密钥的hashCode
会导致hashCode
方法调用的无限递归,从而导致StackOverflowError
。
使用HashMap
作为HashMap
的密钥是一个坏主意。
您使用的是与键相同的对象名称,因此它是无限循环。
是堆栈溢出。
您使用hashmap本身作为键->这意味着递归->没有退出条件-> StackOverflow。
只需使用一个键(Long, String, Object,任何你想要的)。
是的,正如Seek Addo建议的那样,添加带有<>括号的类型