Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HashMap way of doing containsKey not behaving as expected

Today I was doing some pathfinding when I had to use contains() to find if a class Coord was in an other keySet() of Coord. I found that when I used to premade method containsKey(), it was simply not working as I wanted. I made a test to find out what is happening and here it is:

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);

And surprisingly, here is what I found :

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

I just wanted to know what is happening and why.

Also, here is the 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;
    }
}
like image 287
Pâris Douady Avatar asked Feb 10 '23 16:02

Pâris Douady


1 Answers

HashMaps find objects by their hash code. Part of the contract is that the key class must override hashCode() as well as equals(). The default hash codes for separate objects aren't equal, so the object isn't found by get. In contrast, when you loop over all entries, the hash code isn't used, so only equals is called, and the object is found.

To find it using get, override hashCode in Coord.

It is always good to override hashCode whenever you override equals, and vice versa.

like image 97
rgettman Avatar answered Feb 12 '23 07:02

rgettman