我有一个有趣的情况,我将Coordinate
存储到HashMap<Coordinate, GUIGameField>
。
现在,关于它的奇怪之处在于,我有一个代码片段,应该保护,不应该使用两次坐标。但是如果我调试这段代码:
if (mapForLevel.containsKey(coord)) {
throw new IllegalStateException("This coordinate is already used!");
} else {
...do stuff...
}
... containsKey
总是返回false
,虽然我将一个哈希码为9731的坐标存储到地图中,当前的coord也有哈希码9731。
之后,mapForLevel.entrySet()
看起来像:
(java.util.HashMap$EntrySet) [(270,90)=gui.GUIGameField@29e357, (270,90)=gui.GUIGameField@ca470]
我可能做错了什么?我没有想法了。谢谢你的帮助!
public class Coordinate {
int xCoord;
int yCoord;
public Coordinate(int x, int y) {
...store params in attributes...
}
...getters & setters...
@Override
public int hashCode() {
int hash = 1;
hash = hash * 41 + this.xCoord;
hash = hash * 31 + this.yCoord;
return hash;
}
}
答案 0 :(得分:5)
除equals
外,您还应覆盖hashCode
才能正常使用。
编辑:我错误地说你应该在hashCode
中使用equals
- 这是不正确的。虽然hashCode
必须为两个相等的对象返回相同的结果,但它仍然可以为不同的对象返回相同的结果。
答案 1 :(得分:3)
您似乎忘了为您的坐标类实现equals()
方法。这是合同所要求的。 Hah使用equals将2个条目与相同的哈希码进行比较。在你的情况下,调用Object.equals()
对于2个不同的对象总是不同的,因为它基于对内存中对象的引用。
答案 2 :(得分:1)
你需要在hashCode旁边实现equals的原因是哈希表的工作方式。
哈希表将整数值(Key的哈希值)与Value相关联。 可以将其视为Value对象的数组。当您在此表中插入时, value 将存储在 key.hashCode()的位置。
这允许您“直接”找到表格中的任何对象。您只需计算该对象的hashCode,您就会知道它在表中的位置。可以想象它与树相对,在树中你需要导航树以找到对象。)
但是,这种方法存在一个问题:可能存在多个具有相同哈希码的对象。 这会导致您错误地将两个(或更多)键与相同的值相关联。这称为碰撞。
有一种简单的方法可以解决这个问题:您可以将每个哈希码映射到一个 Value ,而不是将其映射到对象列表键值。
现在,每次在哈希映射中查找对象时,在计算哈希值之后,您需要遍历该列表(与该哈希码相关的“值”列表)并找到正确一个。
这就是始终需要在哈希映射的键上实现等于的原因。
注意:哈希表实际上比这更复杂,但想法是一样的。您可以阅读有关冲突解决here的更多信息。
答案 3 :(得分:0)
在hashCode
课程中定义Coordinate
方法。 确保它返回唯一对象的唯一代码,并返回相同对象的唯一代码。