HashMap说键不存在,即使它存在

6

我遇到了一个有趣的问题,我相信它是由于HashMap引起的。请考虑以下调试代码(AMap是一个HashMap,key是传递给此方法的值)

System.out.println("getBValues - Given: " + key);
System.out.println("getBValues - Contains Key: " + AMap.containsKey(key));
System.out.println("getBValues - Value: " + AMap.get(key));
for(Map.Entry<A,HashSet<B>> entry : AMap.entrySet()) {
    System.out.println("getBValues(key) - Equal: " + (key.equals(entry.getKey())));
    System.out.println("getBValues(key) - HashCode Equal: "+(key.hashCode() == entry.getKey().hashCode()));
    System.out.println("getBValues(key) - Key: " + entry.getKey());
    System.out.println("getBValues(key) - Value: " + entry.getValue());
}

现在我向这个地图中插入一个键(通道)和值。稍后,我尝试使用get()获取该值,并运行此调试代码,我的情况下输出如下:

getBValues - Given: Channel(...)
getBValues - Contains Key: false <--- Doesnt contain key?!
getBValues - Value: null   <--- Null (bad)
getBValues(key) - Equal: true <--- Given key and AMap key is equal
getBValues(key) - HashCode Equal: true
getBValues(key) - Key: Channel(Same...)
getBValues(key) - Value: []    <--- Not null (This is the expected result)

正如您所看到的,直接从HashMap中获取键并不起作用,但是通过循环,我得到了完全相同的键,这意味着它存在,只是无法使用get()找到。我的问题是什么会导致这种情况?get()如何找不到存在的键?
我想提供一些示例代码,但似乎无法单独重现此问题。
有什么建议可能会导致这种情况?

4
"我相信这是 HashMap 的错"。请重复一遍,"这个 bug 在我的代码里。" - http://programmers.stackexchange.com/questions/1785/what-should-every-programmer-know-about-programming/1842#1842 - Stephen C
@Stephen 我的意思是“HashMap中的某些‘特性’导致了这个问题”。 - TheLQ
2个回答

8

我使用了Project Lombok,甚至在类中特别排除了2个HashSet,以避免影响相等性。 - TheLQ
我不知道Project Lombok是什么;我无法确定这是否意味着“是的,我有一个适当的equals和hashCode实现。” 最好键也是不可变的。您的通道是否符合这个要求? - duffymo
1
在这个特定的测试中,hashCode为键和存储键提供了相同的值。它可能被错误地或正确地实现,但是在这个实例中它是正确的。key.equals(entry.key)也为true。我能看到的唯一剩下的原因是entry.key.equals(key)为false。 - Vladimir Dyuzhev
抱歉,没错的。哈希码已经正确实现了。请看这里:http://projectlombok.org/features/EqualsAndHashCode.html - TheLQ
+1 就是这样!我没有在代码中覆盖 hashCode,导致键不能按预期工作。非常感谢 xD! - AgentKnopf
1
重写 hashCode 对我很有帮助。因为之前我只重写了 equals,但是你应该同时重写两个方法才能使其正常工作。谢谢。 - Andrii Kovalchuk

4

从我所看到的,我们仍然不能排除与不变性有关的可能性。 如果您这样做:

aMap.put(key, value);
key.setFieldIncludedInHashCodeAndEquals(25);

然后您将从上面得到结果。

为了排除这种情况,要么向我们展示更多的代码,要么在上述示例中的for循环中添加以下内容:

System.out.println(aMap.get(entry.getKey()));

此外,使用调试器。这样,您可以看到您的对象是否在正确的桶中。

嗯...这给了我一个空值。我猜hashCode在添加后发生了变化。我会看看能否更新我的代码以使其可用。 - TheLQ
那么,在您将对象添加到aMap中作为键时,hashCode或equals中的任何字段是否发生更改? - Buhb
这就是为什么映射中的键必须是不可变的原因。 - duffymo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接