i overrided hashCode() and equals() in a class (Dog) in order to store and retrieve it’s instances from a hashMap, the code is as follows:
class Dog {
public Dog(String n) {
name = n;
}
public String name;
public boolean equals(Object o) {
if ((o instanceof Dog)
&& (((Dog) o).name == name)) {
return true;
} else {
return false;
}
}
public int hashCode() {
return name.length();
}
}
and the hashMap code is as follows:
public class MapTest {
public static void main(String[] args) {
Map<Object, Object> m = new HashMap<Object, Object>();
m.put("k1", new Dog("aiko"));
Dog d1 = new Dog("clover");
m.put(d1, "Dog key"); // #1
System.out.println(m.get("k1"));
String k2 = "k2";
d1.name = "arthur"; // #2
System.out.println(m.get(d1)); #3
System.out.println(m.size());
}
}
the problem is that, at 2 i changed the name of the dog object that’s stored inside the hashMap at 1, the expected output at 3 is NULL but the actual is Dog Key!! i expect it to fail in the equals() method as clover!=arthur but it succeds!! i noticed that when the hashCode succeds (i.e. the lengh==6) the value stored in the map is retrieved even though the equals() method fails, i changed == and used equals() instead but no changes happens, the problem remains.
Why does
equals“never fail”?As per Tom’s comment:
That is, the line:
Is mutating the object already in the HashMap. Compare with (where
t“prints” true or false):So the
equalsnever fails because it is comparing the object with itself 🙂I missed it at first too: remember Java has Call By Object-Sharing semantics. That is, there is no implicit Copy/Clone/Duplicate for objects that are passed to methods.
So then, how to get it to fail:
And how does the
hashCodefit in?The hash code is used to determine the hash table bucket to put the key (and value pair) in. When performing a look-up (or set) the bucket is first looked up by hash code and then each key already mapped to the bucket is checked with
equals. If there are no keys in the bucket then equals is never invoked.This explains why changing the
nameto a String of length 8 in the original post results in a failing look-up: a different bucket (say, one that is empty) is initially chosen and thusequalsis never invoked upon existing keys which exist in other buckets. The same object key might be already there, but it’s never looked at!So then, how to get it to fail with different hash code:
Thus, for a key to be found in a hash table (such as a HashMap) it must be such that:
There may be many hash codes that map to the same bucket. However the above is the only guarantee that a look-up will be successful.
Of course, see the other replies for correct way to compare strings in general.