0

I have an object which has one field- double[] _myField it's hashcode is

public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + Arrays.hashCode(_myField);
    return result;
}

However if I used the object as a key in a Map I get the following weird behavior:

for (Map.Entry<MyObject, String> entry: _myMap.entrySet())
    {
         if (entry.getValue() != _myMap.get(entry.getKey()))
         {
                 System.out.println("found the problem the value is null");

         }

    }

The only reason I can think of that the above IF statement is true is that I get a different hashcode for the key.

in fact, I have changed the hashcode function to return 1 in all cases. Not efficient, but good for debugging and indeed the IF statement is always false.

What's wrong with Arrays.hashcode()?

Pls note (after reading some comments): 1) As for the usage of != in the IF statement, indeed it compares references but in the above case it should have been the same. Anyhow the weird thing is that the right hand side returns NULL 2) As for posting Equals function. Of course I've implemented it. But it is irrelevant. Tracing the code in debug reveals that only hashcode is called. The reason for that is presumably the weird thing, the returned hashcode is different from the orignal one. In such cases the Map doesn't find a matching entry and therefore there is no need to call Equals.

Dudi
  • 2,340
  • 1
  • 24
  • 39
  • 7
    Can you also post your implementation of MyObject.equals()? – ben_w Nov 02 '11 at 13:21
  • I can but it is irrelevant. since when I traced in debug mode the hashcode function was called and yielded a different hashcode than the original. Given that the Java map implementation did not get to call equals. It wasn't necessary. – Dudi Nov 02 '11 at 23:30
  • 2
    Interesting! Can you post enough code for us to reproduce the problem ourselves? – ben_w Nov 03 '11 at 03:01

3 Answers3

5

Is the array being changed while it's in the map? Because that will change the outcome of the result.

corsiKa
  • 81,495
  • 25
  • 153
  • 204
  • 1
    +1. Even it it's not being changed, it's a bad idea to use something with a hash code that might change as a HashMap key or in HashSets. – G_H Nov 02 '11 at 13:41
  • as can be seen in the answer, the array did change. – Dudi Dec 07 '11 at 14:22
2

Implementing hashCode is not enough. You also need to implement equals object. In fact whenever you implement hashCode for an object, you MUST implement equals as well. Those 2 work together.

You need to implement equals for your object and ensure that whenever equals is true for 2 objects, their hashCode also matches.

anio
  • 8,903
  • 7
  • 35
  • 53
  • 4
    != compares the object references and does not call equals – Gandalf Nov 02 '11 at 13:27
  • 3
    @Gandalf: this is irrelevant for the problem, though. if equals and hashCode were implemented correctly, the value obtained from the entry should be identical to the value obtained by the get method. – JB Nizet Nov 02 '11 at 13:36
  • @JBNizet I know, but this comment was very relevant to the answer it commented (see its edit history) ;) And I didn't want some people to start to believe that != behaves like this. – Gandalf Nov 02 '11 at 13:48
  • "In fact whenever you implement hashCode for an object, you MUST implement equals as well" - this is incorrect. All that matters is that two objects that are equal have the same hash code. You are free to change hashCode as long as two equals objects has the same hash code. – Steve Kuo Nov 02 '11 at 15:38
  • @SteveKuo Right, that is what matters, but if you provide your own hashCode implementation, how can you guarantee it matches what equals returns if you don't overload it, huh? Magic? – anio Nov 02 '11 at 15:43
  • By code inspection. hashCode can't use any more fields than equals uses. – Steve Kuo Nov 02 '11 at 17:15
  • Extreme example, I override hashCode to return 1 without changing equals. This still maintains the hashCode contract. – Steve Kuo Nov 02 '11 at 18:29
  • I didn't list the equals in the post, but of course I have implemented it. Furthermore, when run in debug mode it is clear that the hashcode is called and it yields a different hashcode than the original one. Thus equals is not even called. E.g. Map implementations first check hashcode and if this is a match it will check equals. – Dudi Nov 02 '11 at 23:26
  • As for !=, indeed it compares references but in the above case it should have been the same. Anyhow the weird thing is that the right hand side returns NULL – Dudi Nov 02 '11 at 23:32
0

Trying to reproduce the problem on a clean slate revealed it is not reproducible.

Hence, further investigation revealed that the problem was the _myField used for Hash was changed while the object was stored in the map. As expected the map is corrupted.

Sorry for the time wasted by those who tried to answer the wrong question.

Dudi
  • 2,340
  • 1
  • 24
  • 39