Reputation: 13517
This is the class that we will use to put into a hasmap. It has overriden both equals()
and hashcode()
methods.
class Dog
{
public String name;
public Dog(String n)
{
name=n;
}
@Override
public int hashCode() {
System.out.println("in hashcode");
return name.length();
}
@Override
public boolean equals(Object obj) {
System.out.println("in equals");
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Dog other = (Dog) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
This code in main
Map<Object,Object> m=new HashMap<Object,Object>();
Dog d1=new Dog("clover");
m.put(d1,"Dog Key");
System.out.println(m.get(d1));
produces
in hashcode
in hashcode
Dog Key
but the following code
Map<Object,Object> m=new HashMap<Object,Object>();
Dog d1=new Dog("clover");
m.put(d1,"Dog Key");
System.out.println(m.get(new Dog("clover")));
produces
in hashcode
in hashcode
in equals
Dog Key
As you can see there is a call to equals()
method in the second output. Why is that so?
My second question
If I change the name attribute of the key
Map m=new HashMap();
Dog d1=new Dog("clover");
m.put(d1,"Dog Key");
d1.name="arthur";
System.out.println(m.get(new Dog("clover")));
the o/p is
in hashcode
in hashcode
in equals
null
even though I have changed the key value, but I am trying to retrieve the value by giving an identical key. Then why does it retrieve null?
Upvotes: 1
Views: 287
Reputation: 154
Lets consider how HashMap works.
Using proper hashcode alghorithm and capacity settings for the HashMap allows to reach O(1) performace on put and get in general.
Now lets consider your questions:
But if you change your code in this:
Dog d1=new Dog("clover");
m.put(d1,"Dog Key");
d1.name="arthur";
System.out.println(m.get(d1));
It should give you atrhur in the end.
Upvotes: 1
Reputation: 4588
This is because after you put your d1=new Dog("clover")
into hashmap, you change its name by d1.name="arthur";
so Dog with name arthur
is no longer equal to new Dog("clover")
.
So at first the key hashcode is checked first and it matches as "clover".length
is equal to "arthur".length
and this lets identify the bucket where your object is held. After that an equals()
check is performed to get the right object from the bucket and this fails as your key is not equal to the one provided.
Actually, it is not a good practice to use mutable fields for hashcode calculation.
Upvotes: 1
Reputation: 81684
For the first question: the HashMap
needs to call equals()
to confirm that the two Dog
objects which both have the same hash code are in fact equal. It doesn't need to call equals()
the first time because it uses ==
to check for the special case of using the exact same object as previously specified.
For the second question: you changed a data member which changes the calculation of the hash code and the result of equals()
. This is specifically against the rules, and as a result the map is corrupted; at that point, anything can happen. Never use objects with mutable data for keys in a HashMap
!
Upvotes: 3