PixelMaster
PixelMaster

Reputation: 954

HashMap.get() doesn't return the proper value, thanks to "hashCode()"

I'm currently working on a TD game with a map editor. Now obviously, you can save and load these maps (or should be able to, at least). Problem is: at some point I'm calling .get() on a HashMap. Unfortunately, the keys that should be the same (logic-wise) are not the same object (in terms of reference), and, according to my previous google research, overriding their .equals method isn't sufficient, since they still return different hashes with .hashCode() (I verified that, they DO return different hashes, while .equals does return true).
(On a side note, that's rather confusing, since the javadoc of HashMap.get(key) only states that they have to be equal)

More specifically, the HashMap contains instances of a class Path of mine as keys, and should return the corresponding list of enemies (= value).

short version of Path (without getters etc.):

public class Path
{
    private List<Tile> tiles = new ArrayList<>();
    @Override
    public boolean equals(Object obj) {
        //code comparing the two paths
    }
    @Override
    public int hashCode() {
        //what I still need to implement. ATM, it returns super.hashCode()
    }
}

public class Tile
{
    private int x;
    private int y;
    //constructor
    //overrides equals
    //getters & some convenience methods
}

Now if two Paths are equal, I'd like them to return the same hash code, so that the HashMap returns the correct list of enemies. (I'll make sure not two identical paths can be added).

Now my question:

Do you suggest

  1. using some external library to generate a hash
  2. that I write my own implementation of calculating a hash, or
  3. something else

?

Note that I'd prefer to avoid changing the HashMap to some other type of map, if that would even help solve the problem.

Upvotes: 0

Views: 1169

Answers (2)

lexicore
lexicore

Reputation: 43651

You definitely do need to implement your hashCode consistent with equals. IDEs often do decent job generating hashCode and equals. Also consider Objects.equals(...) and Objects.hash(...).

One warning about using Path as keys in the HashMap. You will have to make the class immutable to make it work reliably. Or at least make sure that hashCode of the key does not change. Otherwise you may not able to get you data back even with the same or equal key.

Upvotes: 2

Murat Karag&#246;z
Murat Karag&#246;z

Reputation: 37584

The List has a useful method which conveniently is also named list.hashCode(). This will compute the hashCode of all the elements inside the list. So you also have to implement the hashCode for Tile which probably consist of some primitive fields or such.

e.g.

 @Override
    public int hashCode() {
         return tiles != null ? tiles.hashCode() : 0;
    }

See the docs here

int hashCode()
Returns the hash code value for this list. The hash code of a list is defined to be the result of the following calculation:

  int hashCode = 1;
  for (E e : list)
      hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());

This ensures that list1.equals(list2) implies that list1.hashCode()==list2.hashCode() for any two lists, list1 and list2, as required by the general contract of Object.hashCode().

Upvotes: 1

Related Questions