简体   繁体   中英

Java HashMap containsKey always false

I have the funny situation, that I store a Coordinate into a HashMap<Coordinate, GUIGameField> .

Now, the strange thing about it is, that I have a fragment of code, which should guard, that no coordinate should be used twice. But if I debug this code:

if (mapForLevel.containsKey(coord)) {
    throw new IllegalStateException("This coordinate is already used!");
} else {
    ...do stuff...
}

... the containsKey always returns false , although I stored a coordinate with a hashcode of 9731 into the map and the current coord also has the hashcode 9731.

After that, the mapForLevel.entrySet() looks like:

(java.util.HashMap$EntrySet) [(270,90)=gui.GUIGameField@29e357, (270,90)=gui.GUIGameField@ca470]

What could I have possibly done wrong? I ran out of ideas. Thanks for any help!

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

You should override equals in addition to hashCode for it to work correctly.

EDIT : I have wrongly stated that you should use hashCode in your equals - this was not correct. While hashCode must return the same result for two equal objects, it still may return the same result for different objects.

It seems that you forgot to implement equals() method for your coordinate class. This is required by contract. Hah compares 2 entries with the same hash code using equals. In your case the Object.equals() is called that is always different for 2 different object because is based on reference to the object in memory.

The reason why you need to implement equals alongside with hashCode is because of the way hash tables work.

Hash tables associate an integer value (the hash of the Key) with the Value. Think of it as an array of Value objects. When you insert in this table, value is stored at position key.hashCode() .

This allows you to find any object in the table "straight away". You just have to compute the hashCode for that object and you'll know where it is on the table. Think of it as opposed to a Tree, in which you would need to navigate the tree to find the object).

However, there is a problem with this approach: there might be more than one object with the same hash code . This would cause you to mistakenly associate two (or more) keys with the same value. This is called a collision .

There's a simple way to solve this problem: instead of mapping each hashcode to one Value , you can map it to a list of pairs Key-Value .

Now every time you're looking for an object in the hash map, after computing the hash you need to go through that list (the list of 'values' that are related to that hashcode) and find the correct one.

This is why you always need to implement equals on the key of the hash map.

Note: Hash tables are actually a bit more complex than this, but the idea is the same. You can read more about collision resolution here .

Define hashCode method in your Coordinate class. Make sure it returns unique code for unique objects and same for same objects.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM