hashcode() and equals() : Overview
hashcode()
and equals()
methods are defined in java.lang.Object
class which is the super class of all classes in java and hence may be overridden in any class.
-
- The signature of
hashcode()
method ispublic int hashCode()
which means it should return an integer, and - The signature of
equals()
method looks likepublic boolean equals(Object obj)
which means it returns a boolean value indicating whether the object which called it is equal to the object which is passed as an argument to it or not.
- The signature of
Why Override hashcode() and equals() : Practical Scenario
Ever came across putting the objects of your own classes into a hash based collection (Hash based collections are those which use a hashcode to determine the location at which to store the objects such as a java.util.HashSet
, java.util.HashMap
etc.) and getting them back.
If so, then you might know that a HashSet only keeps distinct objects and over writes a previously stored object with a later added equal object. Have you thought how does HashSet know which two objects are the same and which are distinct. It is because of the hashCode()
and equals()
method.
hashCode() and equals() : Importance in Collections
hashCode() : Every object has a hashcode and can be considered as a unique code related to an object of a class. But hashcode of an object becomes extremely important when it comes to Collections. Here is how :
- When inserting an object into a Collection, its hashcode determines the location in that collection where the object will be stored.
- When retrieving the object from a Collection, again its hashcode is used to find the location where it might have been stored.
equals() : The equality of objects is checked using equals() method. Again, this method becomes extremely important when it comes to Collections. Here is how :
- When retrieving the object from a Collection, hashcode is used to find the location where it might have been stored and after fetching, equals method is invoked on the object being fetched passing the object fetched from the collection to it as an argument.
- equals() method checks the objects to be equal and returns the object if it finds them equal else returns null.
It might be clear now that hashCode() method invoked on an object multiple times should return the same value otherwise an object inserted into a collection could NEVER be found.
Similarly, if two objects are considered to be equal on the basis on some property, then calling equals() method on objects having same property value should return true.
Coming to the point, how to override hashCode()
and equals()
method in our class. Just shown below :
public class Book {
/* Properties of class */
String bookName;
int serialNum;
/*
* Override hashCode method to return custom hash codes
*/
public int hashCode() {
int h = 0;
// hash calculation
int len = bookName.toCharArray().length;
for (int i = 0; i < len; i++) {
h = h + 31 * h;
}
return h;
}
/*
* Override equals method according to your equality criteria
*/
public boolean equals(Object o) {
// check if both objects refer to same object, which means they are
// equal. Here this is the object which invoked equals method
if (this == o) {
return true;
}
//check if both objects should be compared or not
if (o instanceof Book) {
// cast to your class to access its fields
Book secondObject = (Book) o;
//check both fields are equal, means objects are equal
if (this.bookName.equals(secondObject.bookName)
&& this.serialNum == secondObject.serialNum) {
return true;
}
return false;
}
return false;
}
public static void main(String[] args) {
// lets use Hashmap as the collection
Map<Book, String> map = new HashMap<Book, String>();
// create an object for storing in map
Book obj = new Book();
// assign values to its variables
obj.bookName = "coDippa";
obj.serialNum = 1;
// store it
map.put(obj, "Stored an object");
// create another object and assign the same parameters to its variables
// in order to make it identical
Book duplicateObject = new Book();
duplicateObject.identifier = "coDippa";
duplicateObject.serialNum = 1;
// search the object and print its value.
// This prints "Stored an object". We found the object back!!
System.out.println(map.get(duplicateObject));
//change one variable and retry finding it
duplicateObject.bookName = "new Value";
//this prints null. The object could not be found
System.out.println(map.get(duplicateObject));
}
}
Detail : In the above example, we have a class named Book
which has two properties, name of the book and its serial number. We create an object (with bookName as “coDippa” and serial number 1) and put it into a map. Then we create a new object with the same property values and search it in the map. We find it !!!. Then we change “bookName” property of this new object and again search it. This time it could not be found. Obviously, since the name is different.
What happens behind the scenes is :
- When putting an object in a collection :
1. Its place in that collection needs to be decided,hashcode()
method is used for this. Our implementation of hashCode calculates a value based on the length of bookName property.
2. Same object is not already present in the collection,equals()
method decides this. Our implementation of equals() checks the book name and its serial number to compare objects.
- When retrieving an object from a collection :
1. The location at which the object is stored is to be determined,hashcode()
method is used for this.
2. The object being returned is the same as requested,equals()
method is again used to decide this.
Note : This post is NOT about the working of HashMap. It only shows how hashcode()
and equals()
method are utilized in Collections and the use and importance of overriding them.
Let’s tweak in
equals()
method defined injava.lang.Object
class just checks the references and nothing else. It will only return true for references pointing to the same object.- The signature of the overridden hashcode and equals method should exactly match with these methods defined in
java.lang.Object
class otherwise they will not be considered to be overridden. - The type of argument of
equals()
method isjava.lang.Object
. This is because it can be overridden in any class andjava.lang.Object
is the superclass of all classes. - Always perform reference check (
if (this == o)
) at the start ofequals()
method. This is to prevent further processing if the objects being compared are the same objects. - The better the implementation of
hashCode()
method, the better is the performance of the Collection since lesser number of objects are stored at the same memory location. hashCode()
method which returns a constant is the poorest implementation since it will return the same location for every object.- In Collections framework,
equals()
method is utilized where ever object comparison is required. For example, incontains(Object o)
method ofjava.util.ArrayList
,java.util.LinkedList
- Both
equals()
andhashCode()
method are utilized in all Hash based Collection classes (java.util.HashSet
,java.util.HashMap
,java.util.TreeMap
etc.) such as input(K key, V value)
method ofjava.util.TreeMap
,java.util.HashMap
,add(E e)
method ofjava.util.HashSet
.
If you are still reading means you liked the post till this point. Do not hesitate to provide your feedback / queries in the space below, specially reserved for this purpose only.