The equals() and hashCode() are methods in java.lang.Object class.This section describes the need of these methods in a class in different scenarios with examples.
1)The equals() method
The == operator in Java compares the bit streams of two object references.It is not inspecting whether the attributes are same or not.So this cannot be used for a meaningful comparison of two objects of a class.For meaningful comparison of objects the equals() method is using. But for meaningful comparison , we cannot trust the default implementation of equals() , without overriding the same in our new class.Because the default implementation internally compares the two objects using == operator. So we cannot identify whether two objects are meaningfully equal or not.
The idea will become clear once we try with the following example.
We have a Student.java class.We are not overriding the equals() method.In the main method we are creating two objects with exactly same attributes.Then we are comparing those two objects using the equals() method.
public class Student { private int id; private String name; public Student(String name, int number) { this.name = name; this.id = number; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public static void main(String[]args){ Student a = new Student("Bijoy",1); Student b = new Student("Bijoy",1); if(a.equals(b)){ System.out.println("both are equal"); }else{ System.out.println("Both are not equal"); } } }
If we are running the application , we gets the output saying both are not equal.
Output
Both are not equal
So for making a meaningful comparison , we need to override the equals() method.In the equals() method we need to specify the criteria by which two objects are meaningfully same.Consider the example discussed above.Here the equality is deciding by comparing the attributes.
Let us see the modified Student.java
public class Student { private int id; private String name; public Student(String name, int number) { this.name = name; this.id = number; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public boolean equals(Object c) { boolean status = false; Student student = (Student) c; if (getId() == student.getId() && getName().equalsIgnoreCase(student.getName())) { status = true; } else { status = false; } return status; } public static void main(String[] args) { Student a = new Student("Bijoy", 1); Student b = new Student("Bijoy", 1); if (a.equals(b)) { System.out.println("both are equal"); } else { System.out.println("Both are not equal"); } } }
Now the output says both the objects are equal
Output
both are equal
So ,we should override the equals() method in our class to make a meaningful comparison.
2)The hashCode() method
It is also a method in the Java.Lang.Object class.It returns an integer value.Suppose there are many slots to in the memory to store an object.The integer returned by hashCode() gives the slot number.There are numerous hashing algorithms .Still researches are going on in making new algorithms to generate efficient hashcodes.If we are making the hashCode() method to return same integer value always , then all objects will be stored in the same memory slot .So searching for a particular object is difficult if there are large number of objects of that class.
Now we are searching for a particular key object in a hashtable.Initially the hashcode of the object is identifying from the search object.Then based on that hashcode , search is doing in particular memory slots.Then comparison using equals() method is doing with all the objects in that slot.So for getting that particular object , the hashcode is also important.
So , if two object are meaningfully same only when
a)The equals()returns true ,and
b)hashcode values are same.
So once we override the equals() method hashCode() also needs to be override ,because identical objects should have the same hashcode.The concept will become more clear when we discuss an example.
We are modifying the above Employee.java class.Here the Student objects are using as key values in a Hashtable.And then we are trying to fetch the value against one object in different scenarios.
1)When hashCode() and equals() are not there.
This case both the methods are not overriding.So using the default implementation of hashCode() and equals() of Object class.
public class Student { private int id; private String name; public Student(String name, int number) { this.name = name; this.id = number; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public static void main(String[] args) { Student a = new Student("Bijoy", 1); Student b = new Student("Karthik", 2); Hashtable<Student,String> table = new Hashtable(); table.put(a,"Bijoy"); table.put(b,"Karthik"); Student student = new Student("Bijoy",1); System.out.println("Value = "+table.get(student)); } }
Output
Value = null
The attributes of objects ‘a’ and ‘student’ are same . But we are using default implementation of hasCode() and equals() methods.Hash code of ‘a’ and ‘student’ are different .The equals() method returns false.So search for key ‘student’ fails , and there is no way to identify the equality of ‘a’ and ‘student’. So null is the output.
2)When equals() only there
Here we are deciding whether two objects are equal or not based on some criteria.Assume attribute ‘id’ is unique.So we are deciding the equality of objects by comparing id.If id’s are same , then the equals() returns true ,else it returns false.
public class Student { private int id; private String name; public Student(String name, int number) { this.name = name; this.id = number; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public boolean equals(Object c) { boolean status = false; Student student = (Student) c; if (getId() == student.getId() && getName().equalsIgnoreCase(student.getName())) { status = true; } else { status = false; } return status; } public static void main(String[] args) { Student a = new Student("Bijoy", 1); Student b = new Student("Karthik", 2); Hashtable<Student, String> table = new Hashtable(); table.put(a, "Bijoy"); table.put(b, "Karthik"); Student student = new Student("Bijoy", 1); System.out.println("Value = " + table.get(student)); } }
Output
Value = null
Here ‘a’ and ‘student’ are having the same attribute values.But the class is using the default implementation of hashCode() method.So hash codes for ‘a’ and ‘student’ are different.(That means, search is taking place in wrong memory slot). Comparison between ‘a’ and ‘student’ is never taking place , because ‘a’ is not in the selected slot. So the search for ‘student’ is never going to work. So null is the output.
3)When hashCode() and equals() are there
Here , we are taking the value of ‘id’ as the hash code. So if two objects are having the same id ,then those objects will be stored in the same memory slot.
public class Student { private int id; private String name; public Student(String name, int number) { this.name = name; this.id = number; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public boolean equals(Object c) { boolean status = false; Student student = (Student) c; if (getId() == student.getId() && getName().equalsIgnoreCase(student.getName())) { status = true; } else { status = false; } return status; } public int hashCode() { return getId(); } public static void main(String[] args) { Student a = new Student("Bijoy", 1); Student b = new Student("Karthik", 2); Hashtable<Student, String> table = new Hashtable(); table.put(a, "Bijoy"); table.put(b, "Karthik"); Student student = new Student("Bijoy", 1); System.out.println("Value = " + table.get(student)); } }
In this case the hash code for ‘a’ and ‘student’ are same. First the search process takes hash code of ‘a’ . Then using that hash code value , it is identifying the memory slot to be searched .Since both ‘a’ and ‘student’ are having same hash code , the search reaches in the correct memory slot where ‘a’ is stored.There it is comparing each object with ‘student’ using equals() method.When it compares ‘student’ and ‘a’ , it returns true since attributes of ‘a’ and ‘student’ are same.So the value stored against ‘a’ is displaying as output.
Output
Value = Bijoy
Summary
1)If we need to use an object as key value in collections like Hashtable or HashMap we should override both equals() and hashCode() methods of java.Lang.Object class in proper way.
2)Different objects can have either same or different hash code values
3)Same objects should have same hash code value.