I have read through Java docs pages, but I am not able to explain, why number of calls of hashCode()
and equals()
is varying like this?
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class NumberOfCalls {
int field;
public int getField() {
return field;
}
public NumberOfCalls(int field) {
this.field = field;
}
@Override
public int hashCode() {
System.out.println("In Hashcode method.");
return 10;
}
@Override
public boolean equals(Object obj) {
System.out.println("In Equals Method");
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
NumberOfCalls other = (NumberOfCalls) obj;
if (field != other.field)
return false;
return true;
}
public static void main(String[] args) {
NumberOfCalls object1 = new NumberOfCalls(5);
NumberOfCalls object2 = new NumberOfCalls(6);
NumberOfCalls object3 = new NumberOfCalls(5);
Set<NumberOfCalls> set = new HashSet<NumberOfCalls>();
set.add(object1);
set.add(object2);
Iterator<NumberOfCalls> it = set.iterator();
System.out.print("Size of set is : " + set.size()
+ "\nObject fields values present in set are : ");
while (it.hasNext()) {
System.out.print(it.next().getField() + " ");
}
System.out.println("\n---------------------------------------------------");
System.out.println("Now checking number of calls -- ");
System.out.println("Object1 is present in set ? - " + set.contains(object1)+"\n");
System.out.println("Object2 is present in set ? - " + set.contains(object2)+"\n");
System.out.println("Object3 is present in set ? - " + set.contains(object3)+"\n");
}
}
Output for above code is
In Hashcode method.
In Hashcode method.
In Equals Method
Size of set is : 2
Object fields values present in set are : 6 5---------------------------------------------------
Now checking number of calls --
In Hashcode method.
In Equals Method
Object1 is present in set ? - trueIn Hashcode method.
Object2 is present in set ? - trueIn Hashcode method.
In Equals Method
In Equals Method
Object3 is present in set ? - true
Questions:
hashCode()
and equals()
called one-one time in case of object1
but not object2
(only hashCode()
is called in this case)? equals()
is called twice in case of object3
? When you add an element to a Set
it gets stored in a Map
internally where key is the object you pass in and value is set to null
. Internally Map
maintains an array (buckets) of linked list. These arrays can also be referred as buckets. The index of the bucket is evaluated using hashCode()
method.
In your case since hashCode() returns a constant value, all values put into Set will go in the same bucket. So for the first call set.add(object1)
internal structure will be something like
bucket [object1 -> null]
Since each bucket contains a linked list, elements stored in the list has a pointer to the next element. Since only one element is added to the list, pointer points to null
.
For next call set.add(object2)
data structure will look like
bucket [object2 -> object1 -> null]
Now whenever you call set.contains(some_object)
, hashCode()
will be called to find out correct bucket. This call also returns reference to the first element.
Answer to first question:
So when you call set.contains(object2)
it actually returns reference to object2
. Now if you look at the HashMap
class' code it first compares if this reference is same as the reference passed in, using ==
operator. Since in this case it is same so it does not call equals()
method. Below is the code snippet from HashMap
class:
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
return e;
This should explain your first question.
Answer to second question:
When you call set.contains(object3)
, bucket index is calculated and reference to object2
is returned. Now object2 == object3
returns false so Map calls object3.equals(object2)
method (first call to equals()
method) to check if both objects are meaningfully equivalent. This also returns false
, so it traverses list and returns reference to the next element in the list, which is object1
.
Again object1 == object3
returns false so Map calls object3.equals(object1)
(second call to equals()
method) method to check if both objects are meaningfully equivalent.
This results in 2 calls to equals()
method.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.