奇怪的Java HashMap行为找不到匹配的对象
我在试图在java.util.HashMap
中找到一个密钥时遇到了一些奇怪的行为,我想我遗漏了一些东西。代码段基本上是:
HashMap<Key, Value> data = ...
Key k1 = ...
Value v = data.get(k1);
boolean bool1 = data.containsKey(k1);
for (Key k2 : data.keySet()) {
boolean bool2 = k1.equals(k2);
boolean bool3 = k2.equals(k1);
boolean bool4 = k1.hashCode() == k2.hashCode();
break;
}
这种奇怪的for循环是存在的,因为对于特定的执行我碰巧知道data
此时只包含一个项,它是k1
,实际上bool2
、bool3
和bool4
在该执行中将被计算为true
^但是,{false
,并且v
将为空
现在,这是一个更大程序的一部分-我无法在更小的样本上重现错误-但在我看来,无论程序的其余部分做什么,这种行为永远不会发生
编辑:我已经手动验证了哈希代码在对象插入到映射和查询对象之间没有变化。我会继续检查这个场地,但还有其他选择吗
# 1 楼答案
从映射接口的API描述中:
此外,对于用作映射键的类型,equals()和hashCode()的行为有非常具体的要求。不遵守此处的规则将导致各种未定义的行为
# 2 楼答案
如果equals()为两个对象返回true,则hashCode()应返回相同的值。如果equals()返回false,则hashCode()应返回不同的值。 供参考:
http://www.ibm.com/developerworks/java/library/j-jtp05273.html
# 3 楼答案
这个应用程序是多线程的吗?如果是这样,另一个线程可以在
data.containsKey(k1)
调用和data.keySet()
调用之间更改数据# 4 楼答案
也许关键类看起来像
# 5 楼答案
如果您确定哈希代码在插入密钥和执行包含检查之间没有变化,那么某个地方就出了严重的问题。您确定使用的是
java.util.HashMap
而不是某种类型的子类吗?您知道您正在使用的JVM实现是什么吗以下是Sun 1.6.0_20 JVM中
java.util.HashMap.getEntry(Object key)
的源代码:如您所见,它检索
hashCode
,转到表中相应的插槽,然后对该插槽中的每个元素执行equals
检查。如果这是您正在运行的代码,并且密钥的哈希代码没有更改,那么它必须执行等于检查,该检查必须失败下一步是为我们提供更多的代码或上下文—至少是密钥类的
hashCode
和equals
方法或者,如果可以的话,我建议连接到调试器。观察您的密钥散列到哪个存储桶,并通过containsKey检查查看失败的地方
# 6 楼答案
如果密钥的哈希代码在插入到映射后发生更改,则可能发生此行为
以下是您描述的行为示例: