当尝试获取其中存在的对象时,Hashmap 给出 Null

发布于 2024-11-18 19:51:32 字数 1128 浏览 2 评论 0原文

我遇到了这个奇怪的问题,我正在迭代响应列表。当我尝试从问题的每个响应中获取答案时,大多数人都正确地得到了答案,除了从哈希映射中获取答案给出 null 的情况。我已经在 Eclipse 中运行了调试模式,并将我尝试从 hashmap getAnswerMap() 获取其值的问题与该 hashmap 中的值进行了比较,两者似乎完全相同,但我仍然得到 null。

for (SurveyResponse response : responses) {
      MultipleChoiceAnswer answer = (MultipleChoiceAnswer) response.getAnswerMap().get(question);
        ....
        ....
      }

然后,我认为这是一个哈希码问题,所以我添加了另一行丑陋的代码来检查哈希码,它们实际上具有相同的哈希码,并且附加的以下行有效并且确实正确设置了答案。

for (SurveyResponse response : responses) {
      MultipleChoiceAnswer answer = (MultipleChoiceAnswer) response.getAnswerMap().get(question);
      for (Entry entry: response.getAnswerMap().entrySet()) {
        if (entry.getKey().hashCode() == question.hashCode()) answer = (MultipleChoiceAnswer) entry.getValue();
        ....
        ....
      }

然而,这非常丑陋,我真的很想从哈希图中得到正确的答案。有什么建议吗?

更新: 对两个对象同时调用 hashCode() 和 equals() 方法表明两者具有相同的哈希码,并且 equals() 返回 true。我怀疑,正如下面的答案之一所表明的那样,问题可能是在将问题插入哈希映射时使用不同的哈希码插入的。因此,调用相关 get 方法会返回 null,因为我尝试获取的对象没有与旧对象相同的哈希码。非常有帮助的答案伙计们!

I am running into this weird issue where I am iterating over a list of responses. when I try to get the answer from each response by the question, most of them get the answer correctly except one where getting the answer from the hashmap gives null. I have ran the debug mode in eclipse, and compared the question that I try to get its value from the hashmap getAnswerMap() with the one inside that hashmap and both seem to be exactly the same, but I still get null.

for (SurveyResponse response : responses) {
      MultipleChoiceAnswer answer = (MultipleChoiceAnswer) response.getAnswerMap().get(question);
        ....
        ....
      }

Then, I thought it is a hashcode issue, so I added another ugly line of code to check hashcodes, and they actually have the same hashcode and the additional following line worked and did set answer correctly.

for (SurveyResponse response : responses) {
      MultipleChoiceAnswer answer = (MultipleChoiceAnswer) response.getAnswerMap().get(question);
      for (Entry entry: response.getAnswerMap().entrySet()) {
        if (entry.getKey().hashCode() == question.hashCode()) answer = (MultipleChoiceAnswer) entry.getValue();
        ....
        ....
      }

However, this is very ugly and I would really like to get the answer correctly from the hashmap. Any suggestions?

UPDATE:
calling both hashCode() and equals() method on both objects shows that both have equal hashcodes and equals() returns true. I suspect that as one of the answers down indicate, the problem might be that the question was inserted with a different hashcode when it was inserted in the hashmap. Therefore, calling the get method in question returns null because the object I am trying to get does not have the same hashcode as the old one. Extremely helpful answers guys!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

扬花落满肩 2024-11-25 19:51:32

需要注意的一件事:确保您用作键的类是不可变的 - 否则,当您将键放入时,它会散列为一件事,但当您取时会散列为不同的东西它出来了。

编辑:它不一定是不可变的,但它必须是真实的,它只能以不改变哈希码的方式进行更改。使整个对象不可变是最简单的方法,但这不是唯一的方法。

One thing to watch out for: Make sure the class you're using as a key is immutable -- otherwise, a key will hash to one thing when you put it in, but something different when you take it out.

Edit: It doesn't have to be immutable, but it has to be true that it can only be changed in a way that doesn't change the hashcode. Making the entire object immutable is the simplest way to do that, but it's not the only way.

日久见人心 2024-11-25 19:51:32

另一种玻璃球猜测:

您有一个像这样的 equals 方法:

class Question {

    // ...


    public boolean equals(Question q) {
       // do intelligent comparison
    }

    public int hashCode() {
        // calculate hash code
    }

}

但是在这里您并没有真正从 Object 重写 equals(Object) 方法,而只是声明一个除此之外还有新的。 HashMap 对您的新方法一无所知,它只会调用原始方法来将映射中的键对象与查询键进行比较(在找到具有匹配 hashCode 的键之后)。

相反,请像这样声明该方法:(

    @Override
    public boolean equals(Object o) {
        if(! (o instanceof Question))
           return false;
        Question q = (Question)o;
        // do intelligent comparison
    }

@Override 注释可让编译器检查您是否确实在此处重写了方法,而不仅仅是创建了一个新方法。)

One more glass ball guess:

You have an equals method like this one:

class Question {

    // ...


    public boolean equals(Question q) {
       // do intelligent comparison
    }

    public int hashCode() {
        // calculate hash code
    }

}

But here you don't really override the equals(Object) method from Object, but simply declare a new one beside this. The HashMap does not know anything about your new method, it will simply call the original one for comparing your key object in the map with the query key (after finding one with matching hashCode).

Declare the method like this, instead:

    @Override
    public boolean equals(Object o) {
        if(! (o instanceof Question))
           return false;
        Question q = (Question)o;
        // do intelligent comparison
    }

(The @Override annotation lets the compiler check that you are really overriding a method here, not just creating a new one.)

债姬 2024-11-25 19:51:32

要使用 HashMap 使对象成为 100% 确定性的键,您需要重写 hashCode()equals(),使它们在以下方面保持一致:当 hashCode() 相同时,equals() 始终返回 true

这是 Brian Goetz 在 IBM DeveloperWorks 上发表的一篇旧文章 ,但内容今天仍然适用:

为什么要重写 equals() 和 hashCode()?

如果 Integer 不存在会发生什么
覆盖equals()hashCode()
如果我们从未使用过Integer,什么也没有
作为 HashMap 或其他中的键
基于哈希的集合。然而,如果我们
使用这样的 Integer 对象
HashMap 中的键,我们不会
能够可靠地检索
关联值,除非我们使用
完全相同的 Integer 实例
get() 调用就像我们在 put() 中所做的那样
称呼。这需要确保
我们只使用一个实例
Integer 对应于一个对象
整个过程中的特定整数值
我们的计划。不用说,这
方法会很不方便,并且
容易出错。

接口合约
对于 Object 要求如果两个
对象是相等的,根据
equals(),那么它们必须具有相同的
hashCode() 值。为什么我们的根
对象类需要hashCode(),当它
辨别能力完全是
包含在 equals() 中吗?这
hashCode() 方法的存在纯粹是为了
效率。 Java平台
建筑师预见到了其重要性
基于哈希的集合类——
例如 HashtableHashMap
HashSet——典型的 Java 中
应用程序,并进行比较
许多带有 equals() 的对象可以
计算成本昂贵。拥有
每个Java对象都支持hashCode()
允许有效的存储和
使用基于哈希的检索
收藏。

To make an object an 100% deterministic key with a HashMap you need to override hashCode() and equals() where they are consistent in that equals() always returns true when the hashCode()s are the same.

Here is an old article from Brian Goetz on IBM developerWorks, but the contents are still applicable today:

Why override equals() and hashCode()?

What would happen if Integer did not
override equals() and hashCode()?
Nothing, if we never used an Integer
as a key in a HashMap or other
hash-based collection. However, if we
were to use such an Integer object for
a key in a HashMap, we would not be
able to reliably retrieve the
associated value, unless we used the
exact same Integer instance in the
get() call as we did in the put()
call. This would require ensuring that
we only use a single instance of the
Integer object corresponding to a
particular integer value throughout
our program. Needless to say, this
approach would be inconvenient and
error prone.

The interface contract
for Object requires that if two
objects are equal according to
equals(), then they must have the same
hashCode() value. Why does our root
object class need hashCode(), when its
discriminating ability is entirely
subsumed by that of equals()? The
hashCode() method exists purely for
efficiency. The Java platform
architects anticipated the importance
of hash-based collection classes --
such as Hashtable, HashMap, and
HashSet -- in typical Java
applications, and comparing against
many objects with equals() can be
computationally expensive. Having
every Java object support hashCode()
allows for efficient storage and
retrieval using hash-based
collections.

兮子 2024-11-25 19:51:32

您可能没有正确重写 equals(..) - 这是 HashMap 正常工作的要求

It's likely that you haven't overridden equals(..) correctly - it is a requirement for a HashMap to work correctly

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文