How to make HashMap work properly with custom key

2020-02-07 01:09发布

问题:

I think my question is quite simple, however I couldn't find the solution so I decided to ask here. What i need is to make a HashMap with a custom Key type like this:

HashMap<Pair<Integer, Integer>, StrategyPoint> myMap = new HashMap<Pair<Integer, Integer>, StrategyPoint> ();

However I am missing something here, because the HashMap stops working properly. First the Key becomes not unique and a different instances of Pair with same values can be found in the keySet. Also the contains key function does not work the way I suppose it to :).

I clearly miss something and more likely I should somehow define a way to compare my instances from my Pair class. However I tried implementing Comparable with compareTo in my Pair class and it still don't work. Any suggestions?

My original code is kinda messy and unfriendly to read, so I made an example just to illustrate my problem here.

Here is the code:

HashMap<Pair<Integer, Integer>, StrategyPoint> myMap = new HashMap<Pair<Integer, Integer>, StrategyPoint> ();
    Pair<Integer, Integer> myPair = new Pair<Integer, Integer>(2,2);
    StrategyPoint myPoint= new StrategyPoint(2, 2, 5, 5, false);
    myMap.put(myPair, myPoint);


    Pair<Integer, Integer> searcher = new Pair<Integer, Integer> (0,0);
    searcher.setFirst(2);
    searcher.setSecond(2);
    System.out.println(myMap.containsKey(searcher));
    System.out.println(myMap.containsKey(myPair));

The result from execution is:

false

true

I have debug it and the searcher instance is being populated properly, however it seems the HashMap refuse to find it in its keySet.

回答1:

You must implement properly equals and hashCode on the Pair class.

The HashMap uses these methods to differentiate and hash the key class.



回答2:

You need to override equals in the class Pair. The implementation of this method defines how two objects of Pair are considered equal.

And whenever you override equals you must always override hashcode.

Here is what can go wrong when you override equals but not hashcode (from Effective Java, Second Ed.):

Two distinct instances may be logically equal according to a class’s equals method, but to Object’s hashCode method, they’re just two objects with nothing much in common. Therefore Object’s hashCode method returns two seemingly random numbers instead of two equal numbers as required by the contract.

Because the hashcodes for two logically equal instances become unequal, if you try to search for one while another is in the collection, you will end up looking in the wrong hash bucket which results in null.

There is a set of rules that implementation of equals must conform to. Another set of rules for overriding hashcode.



回答3:

Your Pair class need to implement hashCode() and equals() according to the contract specified in the Javadoc for Object.