The equals() and hashcode() methods

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.

See Related Discussions

Hashtable in Java

HashMap

HashSet

LinkedHashSet

Comparable vs Comparator