HashMap 做 containsKey 的方式不符合预期

HashMap way of doing containsKey not behaving as expected

今天我正在做一些寻路,当我不得不使用 contains() 来查找 class Coord 是否在 Coord 的另一个 keySet() 中时. 我发现当我使用预制方法 containsKey() 时,它根本无法正常工作。我进行了测试以了解发生了什么,这里是:

HashMap<Coord, Coord> test = new HashMap<Coord, Coord>();
test.put(new Coord(3, 3), new Coord(0, 0));

System.out.println("HashMap test for containsKey : " + test.containsKey(new Coord(3, 3)));

boolean containsKey = false;
for(Coord a : test.keySet())
{
    if(a.equals(new Coord(3, 3)))
    {
        containsKey = true;
    }
}

System.out.println("My test for containsKey : "+containsKey);

令人惊讶的是,这是我的发现:

HashMap test for containsKey : false
My test for containsKey : true

我只是想知道发生了什么以及为什么。

此外,这里是 Coord class :

public class Coord
{
    public float x, y;

    public Coord(float a, float b)
    {
        this.x = a;
        this.y = b;
    }

    @Override
    public boolean equals(Object b)
    {
        if(b instanceof Coord)
        {
            Coord casted = (Coord) b;
            return casted.x == x && casted.y == y;
        }
        return false;
    }
}

HashMaps 通过哈希码查找对象。合同的一部分是密钥 class 必须覆盖 hashCode() 以及 equals()。不同对象的默认哈希码不相等,因此 get 找不到该对象。相反,当您遍历所有条目时,不使用散列码,因此仅调用 equals 并找到对象。

要使用 get 找到它,请覆盖 Coord 中的 hashCode

每次覆盖 equals 时覆盖 hashCode 总是好的,反之亦然。

Hashmap 实际上是在 hashing 的基础上工作的。为了获得正确和预期的结果,Hashmap 中使用的密钥应覆盖 equals() 以及 hashCode().

所以在上面,当你在做 test.containsKey(new Coord(3, 3)) 时,你正在创建一个新的 Coord 对象,所以它的哈希码不同于你把它放在地图上的 Object,因为它的调用默认为 Object class hasCode()。所以 containsKey() 给出 false

但是当你在做 a.equals(new Coord(3, 3)) 时你正在调用覆盖 equals() 这满足了你在覆盖方法中设置的条件,这两个 Coord 对象都满足了,所以输出为 true.

为了获得正确的结果,还要正确覆盖 hashCode()

有关 HashMap 如何在 Java 中工作的更多信息,您可以查看此博客 here。希望这对您有所帮助。