Java Hashmap在尝试获取其中存在的对象时提供Null
我遇到了一个奇怪的问题,在这个问题上我重复了一系列的回答。当我试图从每个问题的回答中得到答案时,大多数答案都是正确的,除了一个从hashmap中得到的答案为空。我在eclipse中运行了调试模式,并将我试图从hashmap getAnswerMap()获取其值的问题与hashmap中的问题进行了比较,两者似乎完全相同,但我仍然得到null 对于(调查响应:响应){ multipleChiceAnswer-answer=(multipleChiceAnswer)response.getAnswerMap().get(问题); .... .... } 然后,我认为这是一个hashcode问题,所以我添加了另一行丑陋的代码来检查hashcodes,它们实际上有相同的hashcode,下面的附加行起作用了,并且正确地设置了答案 对于(调查响应:响应){ multipleChiceAnswer-answer=(multipleChiceAnswer)response.getAnswerMap().get(问题); for(条目:response.getAnswerMap().entrySet()){ if(entry.getKey().hashCode()==question.hashCode())answer=(multipleechoiceanswer)entry.getValue(); .... .... } 然而,这很难看,我真的很想从hashmap中得到正确的答案。有什么建议吗 更新:Java Hashmap在尝试获取其中存在的对象时提供Null,java,hashmap,hash,Java,Hashmap,Hash,我遇到了一个奇怪的问题,在这个问题上我重复了一系列的回答。当我试图从每个问题的回答中得到答案时,大多数答案都是正确的,除了一个从hashmap中得到的答案为空。我在eclipse中运行了调试模式,并将我试图从hashmap getAnswerMap()获取其值的问题与hashmap中的问题进行了比较,两者似乎完全相同,但我仍然得到null 对于(调查响应:响应){ multipleChiceAnswer-answer=(multipleChiceAnswer)response.getAnswer
对这两个对象同时调用hashCode()和equals()方法表明这两个对象的hashcodes和equals()都相等返回true。我怀疑下面的一个答案表明,问题可能是在将问题插入hashmap时使用了不同的hashcode。因此,调用问题中的get方法返回null,因为我尝试获取的对象没有与旧对象相同的hashcode。非常有用的answers伙计们!很可能您没有覆盖
equals(…)
正确-需要一个HashMap
才能正常工作需要注意的一件事:确保用作键的类是不可变的——否则,当你放入一个键时,它会散列到一个对象,而当你取出它时,它会散列到另一个对象
编辑:它不必是不可变的,但它必须是真实的,它只能以不改变哈希代码的方式进行更改。使整个对象不可变是实现这一点的最简单的方法,但不是唯一的方法。要使对象成为具有
哈希映射的100%确定性键,需要覆盖哈希代码()
和equals()
在equals()
中一致,当hashCode()
相同时,它们总是返回true
下面是IBM developerWorks上Brian Goetz的一篇老文章,但内容至今仍然适用:
为什么覆盖equals()和hashCode()?
如果Integer
没有,会发生什么
覆盖equals()
和hashCode()
?
如果我们从未使用过整数
作为哈希映射
或其他
基于散列的集合。但是,如果
我们将使用这样一个整数对象
HashMap中的一个键,我们不会
能够可靠地检索
关联值,除非我们使用
完全相同的Integer
实例
get()
调用,就像我们在put()
这需要确保
我们只使用
整数
与
特定整数值
我们的节目,不用说,这
这种方法会很不方便,而且
容易出错
接口合同
对于对象
要求
根据不同的标准,对象是相等的
equals()
,则它们必须具有相同的
hashCode()
value。为什么我们的根
对象类需要hashCode()
,当其
辨别能力完全不同
被equals()
的包含
hashCode()
方法的存在纯粹是为了
效率:Java平台
建筑师们预见到了这一重要性
基于散列的集合类的定义--
例如Hashtable
,HashMap
,以及
HashSet
——在典型的Java中
应用程序,并与
许多具有equals()
的对象可以
计算上很昂贵
每个Java对象都支持hashCode()
允许高效的存储和存储
基于哈希的检索
收藏
还有一个玻璃球猜测:
您有这样一个equals方法:
class Question {
// ...
public boolean equals(Question q) {
// do intelligent comparison
}
public int hashCode() {
// calculate hash code
}
}
但是在这里您并没有真正覆盖对象中的equals(Object)
方法,只需在此旁边声明一个新方法。HashMap对您的新方法一无所知,它只需调用原始方法,将映射中的键对象与查询键进行比较(在找到一个具有匹配hashCode的键对象后)
改为如下声明方法:
@Override
public boolean equals(Object o) {
if(! (o instanceof Question))
return false;
Question q = (Question)o;
// do intelligent comparison
}
(通过@Override
注释,编译器可以检查您是否真的在这里重写了一个方法,而不仅仅是创建了一个新方法。)我刚刚通过system.out.println检查了这一点,entry.getKey().equals(question)返回true。是的,我完全同意您的说法。但是,我同时检查了equals()和hashCode()对于question和entry.getKey()和两者都是一致的。但是hashCode是否与将对象放入映射时的hashCode相同!“其中它们一致,当hashCode()相同时,equals()始终返回true”-事实上-正如你的文章所说-那不是真的。两个不同的对象可能有相同的hashcode,但仍然返回false作为equals,这将是一个完全有效的实现。Hashcollisions是很有可能的。我不知道这为什么会被否决,据我们所知,这可能是问题的解决方案。是和否-你是对的哈希代码必须保持为t