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

时间:2011-07-06 22:47:38

标签: java hashmap hash

我遇到了这个奇怪的问题,我正在迭代一个响应列表。当我试图从问题的每个响应中得到答案时,大多数人都能正确得到答案,除了从hashmap得到答案的答案为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();
        ....
        ....
      }

但是,这非常难看,我真的希望从hashmap中正确地得到答案。有什么建议吗?

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

4 个答案:

答案 0 :(得分:3)

要注意的一件事是:确保您用作密钥的类是不可变的 - 否则,当您将密钥放入时,密钥将散列为一个东西,但不同的东西什么时候拿出来。

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

答案 1 :(得分:2)

还有一个玻璃球猜测:

你有一个像这样的平等方法:

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注释允许编译器检查您是否真的覆盖了一个方法,而不仅仅是创建一个新方法。)

答案 2 :(得分:1)

要使对象成为HashMap的100%确定性密钥,您需要覆盖hashCode()equals(),其中equals()始终返回true hashCode()Integer s相同时。

以下是来自IBM developerWorks的Brian Goetz的旧article,但其内容仍然适用于今天:

  

为什么要覆盖equals()和hashCode()?

     

如果equals()没有,会发生什么   覆盖hashCode()Integer?   没有,如果我们从未使用HashMap   作为Integer或其他内容的关键字   基于散列的集合。但是,如果我们   是使用这样的Integer对象   HashMap中的一个键,我们不会   能够可靠地检索   相关值,除非我们使用了   完全相同的get()实例   我put()调用了Integer   呼叫。这需要确保这一点   我们只使用一个实例   对应于a的Object对象   整个特定的整数值   我们的计划。不用说,这个   方法会很不方便   容易出错。

     

接口合同   对equals()要求如果两个   对象是相等的   hashCode(),然后他们必须有相同的   hashCode()值。equals()为什么我们的根   对象类需要hashCode(),当它的时候   辨别能力完全是   归入Hashtable的那个?该   HashMap方法纯粹存在于   效率。 Java平台   建筑师期待重要性   基于散列的集合类 -   例如HashSetequals()和   hashCode() - 在典型的Java中   应用程序,并进行比较   {{1}}的许多对象都可以   计算上很昂贵。有   每个Java对象支持{{1}}   允许有效的存储和   使用基于散列的检索   集合。

答案 3 :(得分:0)

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