Java HashMap containsKey始终为false

时间:2012-10-14 15:29:20

标签: java hashmap contains

我有一个有趣的情况,我将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;
    }
}

4 个答案:

答案 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方法。 确保它返回唯一对象的唯一代码,并返回相同对象的唯一代码。