Hashcode and Equals method in Java

In Java, equals() and hashCode() methods are defined in Object class. The signature of hashcode and equals method are

public class Object {
    public native int hashCode();

	public boolean equals(Object paramObject) {
		return (this == paramObject);
	}
	
	//other methods...
}

From the above it is clear that equals() method compares the memory reference/location of two objects. Moreover, any class in Java can implement its own version of equals() method and hashCode() method as both of them are public. So, the question is why we require implementing equals() method in Java in other classes if object class provides the implementation of it. As we see that equals() method compares the memory reference of two objects which may not be helpful while comparing two objects. For example String class implements its own version of equals() method to compare two string objects based on the sequence of characters. Similarly in other classes there may be the requirement to confirm two objects are equal based on custom requirement/logic.

Now let us understand hashCode method in detail. To understand hashCode let us first  understand the concept of hashing and bucket. The hashCode of an object is the index of 2D entry table. Hence, any object when stored in memory is stored inside the bucket and JVM first calculates the hashCode() of any object and then stores the object in that bucket. Let us understand this using below diagram.

Hashcode method in Java

From above it is clear that these buckets can contain more than one objects. But does that mean if two objects have the same hashCode they are equal? No, it is not necessary. From the above it is clear that two different objects have same hashCode and land in the same bucket.

According to Java specification:

  • Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer. This integer need not remain consistent from one execution of an application to another execution of the same application.
  • If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.
  • It is not required that if two objects are unequal according to the equals(java.lang.Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results. However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hashtables.

Hence while implementing equals method in any class it is recommended to implement hashCode in that class and follow above mentioned contract between hash code and equals method.

Let us understand how to implement hashCode method using IDE.

Create a class Employee and create two fields as listed below. Create the getter and setter method for these fields.

In this class, we want to implement the custom equals() method  which checks the employeeId of two employees and return true if both are true. While implementing hashCode() method, it is important to understand that there should not be collision in hash values generated for two objects and the distribution of objects to bucket is uniform. Hence, it is suggested to use hashCode generator of IDE for example eclipse.

Right click on file and select source->Generate hashCode() and equals()

 

HashCode and equals method

 Now select the field which you want to consider while generating hashCode.

Generating HashCode method

Now the IDE generates the hashCode() method and equals() method which confirms the contract between hashCode() and equals() method.

public class Employee {
	private int employeeId;       
        private String name;
	public int getEmployeeId() {
		return employeeId;
	}
	public void setEmployeeId(int employeeId) {
		this.employeeId = employeeId;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + employeeId;
		return result;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Employee other = (Employee) obj;
		if (employeeId != other.employeeId)
			return false;
		return true;
	}
	
}

What if hashcode and equals method contract is not satisfied?

 Let us create a class Employee which implements equals() methods which considers two employee objects equal if both have the same employeeId. 

 

public class Employee {
	private int employeeId;
	private String name;
	public Employee(int id, String name) {
		this.employeeId = id;
		this.name = name;
	}
	public int getEmployeeId() {
		return employeeId;
	}
	public void setEmployeeId(int employeeId) {
		this.employeeId = employeeId;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Employee other = (Employee) obj;
		if (employeeId != other.employeeId)
			return false;
		return true;
	}
}

Now let us create a class.

public class Main {
	public static void main(String[] args) {
	
		Employee emp1 = new Employee(123,"Amit");
		Employee emp2 = new Employee(1234,"Ashish");
		HashMap hm = new HashMap();
		hm.put(emp1, "11");
		hm.put(emp2, "123");
		Employee emp3 = new Employee(123,"Amit");
		System.out.println(emp3.equals(emp1));
		String name = (String) hm.get(emp3);
		System.out.println(name);
	}
}

In the above code snippet, we created two Employee objects and used as key in HashMap. Now let us create one more employee object emp3. As we implemented equals() method we considered two objects equal if their employeeId is equal. Hence as per implementation emp1 and emp3 are equal and if we try to find emp3 in HashMap object it should return emp1 as an output. Let us see what happens after executing the above code.

emp3.equals(emp1) returns : true
null

Though both the objects are equal but as we didn't implement hashCode method, default hashCode method was used and it generated different hashCode for emp1 and emp3 objects. 

When we use get method of HashMap it first generates hashCode of the key and compares it with hashCode of objects it holds/contains and once it finds the object with the same hashCode, it compares the value.

In the above case, it generated different hashCode for emp3 and tried to find the key using the hashCode generated for emp3 and was not able to find the key. Hence returned null in the above case. (Remember the contract which states that if two objects are equal their hashCode should be same). Hence, it is recommended to implement hashcode while implementing equals() method.

Now try to implement same code and implement the hashCode() method and see the impact.

Article tagged as
Author
Author: Amit Gupta
Published On: 20/08/2015
Last revised On: 12/04/2016
View all articles by Amit Gupta

Share this post

Comments

Comments
comments powered by Disqus

Navigation

Social Media