Learn about Java hashCode[]
and equals[]
methods, their default implementation, and how to correctly override them. Also, we will learn to implement these methods using 3rd party classes HashCodeBuilder
and
public class Employee
{
private Integer id;
private String firstname;
private String lastName;
private String department;
//Setters and Getters
}
0.1 andpublic class Employee { private Integer id; private String firstname; private String lastName; private String department; //Setters and Getters }
2 methods have been defined inpublic class Employee { private Integer id; private String firstname; private String lastName; private String department; //Setters and Getters }
3 class which is parent class for all java classes. For this reason, all java objects inherit a default implementation of these methods.public class Employee { private Integer id; private String firstname; private String lastName; private String department; //Setters and Getters }
Table of Contents: 1. Uses of hashCode[] and equals[] Methods 2. Override the default behavior 3. EqualsBuilder and HashCodeBuilder 4. Generate hashCode[] and equals[] using Eclipse 5. Important things to remember 6. Special Attention When Using in ORM
1. Uses of hashCode[] and equals[] Methods
4 – verifies the equality of two objects. Its default implementation simply checks the object references of two objects to verify their equality.public class Employee { private Integer id; private String firstname; private String lastName; private String department; //Setters and Getters }
By default, two objects are equal if and only if they are refer to the same memory location. Most Java classes override this method to provide their own comparison logic.
5 – returns a unique integer value for the object in runtime.public class Employee { private Integer id; private String firstname; private String lastName; private String department; //Setters and Getters }
By default, integer value is derived from memory address of the object in heap [but it’s not mandatory].
The object’s hash code is used for determining the index location, when this object needs to be stored in some HashTable like data structure.
1.1. Contract between hashCode[] and equals[]
Overriding the the hashCode[]
is generally necessary whenever equals[]
is overridden to maintain the general contract for the hashCode[]
method, which states that equal objects must have equal hash codes.
- Whenever it is invoked on the same object more than once during an execution of a Java application, the
9[] must consistently return the same integer, provided no information used inpublic class Employee { private Integer id; private String firstname; private String lastName; private String department; //Setters and Getters }
0 comparisons on the object is modified.public class EqualsTest { public static void main[String[] args] { Employee e1 = new Employee[]; Employee e2 = new Employee[]; e1.setId[100]; e2.setId[100]; System.out.println[e1.equals[e2]]; //false } }
This integer need not remain consistent between the two executions of the same application or program. - If two objects are equal according to the
equals[]
method, then calling thehashCode[]
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[]
, then calling thehashCode[]
on each of the both 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 hash tables.
2. Overriding the Default Behavior
Everything works fine until we do not override any of both methods in our classes. But, sometimes, the application needs to change the default behavior of some objects.
Let us understand why we need to override equals and hashcode methods.
2.1. The default behavior of Employee class
Let’s take an example where your application has
public class EqualsTest {
public static void main[String[] args] {
Employee e1 = new Employee[];
Employee e2 = new Employee[];
e1.setId[100];
e2.setId[100];
System.out.println[e1.equals[e2]]; //false
}
}
5 object. Let us create a minimal possible structure of public class EqualsTest {
public static void main[String[] args] {
Employee e1 = new Employee[];
Employee e2 = new Employee[];
e1.setId[100];
e2.setId[100];
System.out.println[e1.equals[e2]]; //false
}
}
5 class:public class Employee
{
private Integer id;
private String firstname;
private String lastName;
private String department;
//Setters and Getters
}
Above
public class EqualsTest {
public static void main[String[] args] {
Employee e1 = new Employee[];
Employee e2 = new Employee[];
e1.setId[100];
e2.setId[100];
System.out.println[e1.equals[e2]]; //false
}
}
5 class has some fundamental attributes and their accessor methods. Now consider a simple situation where you need to compare two Employee objects. Both employee objects have the same public class EqualsTest {
public static void main[String[] args] {
Employee e1 = new Employee[];
Employee e2 = new Employee[];
e1.setId[100];
e2.setId[100];
System.out.println[e1.equals[e2]]; //false
}
}
8.public class EqualsTest {
public static void main[String[] args] {
Employee e1 = new Employee[];
Employee e2 = new Employee[];
e1.setId[100];
e2.setId[100];
System.out.println[e1.equals[e2]]; //false
}
}
No prize for guessing. The above method will print “false.”
But is it correct after knowing that both objects represent the same employee? In a real-time application, this should return
public class EqualsTest {
public static void main[String[] args] {
Employee e1 = new Employee[];
Employee e2 = new Employee[];
e1.setId[100];
e2.setId[100];
System.out.println[e1.equals[e2]]; //false
}
}
9.2.2. Should we override only equals[] method?
To achieve correct application behavior, we need to override equals[]
method as below:
public boolean equals[Object o] {
if[o == null]
{
return false;
}
if [o == this]
{
return true;
}
if [getClass[] != o.getClass[]]
{
return false;
}
Employee e = [Employee] o;
return [this.getId[] == e.getId[]];
}
Add this method to the
public class EqualsTest {
public static void main[String[] args] {
Employee e1 = new Employee[];
Employee e2 = new Employee[];
e1.setId[100];
e2.setId[100];
System.out.println[e1.equals[e2]]; //false
}
}
5 class, and public boolean equals[Object o] {
if[o == null]
{
return false;
}
if [o == this]
{
return true;
}
if [getClass[] != o.getClass[]]
{
return false;
}
Employee e = [Employee] o;
return [this.getId[] == e.getId[]];
}
2 will start returning public boolean equals[Object o] {
if[o == null]
{
return false;
}
if [o == this]
{
return true;
}
if [getClass[] != o.getClass[]]
{
return false;
}
Employee e = [Employee] o;
return [this.getId[] == e.getId[]];
}
3.So are we done? Not yet. Let’s test the above-modified
public class EqualsTest {
public static void main[String[] args] {
Employee e1 = new Employee[];
Employee e2 = new Employee[];
e1.setId[100];
e2.setId[100];
System.out.println[e1.equals[e2]]; //false
}
}
5 class again in a different way.import java.util.HashSet;
import java.util.Set;
public class EqualsTest
{
public static void main[String[] args]
{
Employee e1 = new Employee[];
Employee e2 = new Employee[];
e1.setId[100];
e2.setId[100];
//Prints 'true'
System.out.println[e1.equals[e2]];
Set employees = new HashSet[];
employees.add[e1];
employees.add[e2];
System.out.println[employees]; //Prints two objects
}
}
The above example prints two objects in the second print statement.
If both employee objects have been equal, in a
public boolean equals[Object o] {
if[o == null]
{
return false;
}
if [o == this]
{
return true;
}
if [getClass[] != o.getClass[]]
{
return false;
}
Employee e = [Employee] o;
return [this.getId[] == e.getId[]];
}
5 which stores unique objects, there must be only one instance inside public boolean equals[Object o] {
if[o == null]
{
return false;
}
if [o == this]
{
return true;
}
if [getClass[] != o.getClass[]]
{
return false;
}
Employee e = [Employee] o;
return [this.getId[] == e.getId[]];
}
6 because both objects refer to the same employee. What is it we are missing??2.3. Overriding hashCode[] is necessary
We are missing the second important method hashCode[]
. As java docs say, if we override equals[]
then we must override hashCode[]
. So let’s add another method in our
public class EqualsTest {
public static void main[String[] args] {
Employee e1 = new Employee[];
Employee e2 = new Employee[];
e1.setId[100];
e2.setId[100];
System.out.println[e1.equals[e2]]; //false
}
}
5 class.@Override
public int hashCode[]
{
final int PRIME = 31;
int result = 1;
result = PRIME * result + getId[];
return result;
}
Once the above method is added in Employee class, the second statement starts printing only a single object in the second statement and thus validating the true equality of
import java.util.HashSet;
import java.util.Set;
public class EqualsTest
{
public static void main[String[] args]
{
Employee e1 = new Employee[];
Employee e2 = new Employee[];
e1.setId[100];
e2.setId[100];
//Prints 'true'
System.out.println[e1.equals[e2]];
Set employees = new HashSet[];
employees.add[e1];
employees.add[e2];
System.out.println[employees]; //Prints two objects
}
}
1 and import java.util.HashSet;
import java.util.Set;
public class EqualsTest
{
public static void main[String[] args]
{
Employee e1 = new Employee[];
Employee e2 = new Employee[];
e1.setId[100];
e2.setId[100];
//Prints 'true'
System.out.println[e1.equals[e2]];
Set employees = new HashSet[];
employees.add[e1];
employees.add[e2];
System.out.println[employees]; //Prints two objects
}
}
2.3. EqualsBuilder and HashCodeBuilder
Apache commons provide two excellent utility classes HashCodeBuilder and EqualsBuilder for generating hash code and equals methods.
We can use these classes in the following manner.
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
public class Employee
{
private Integer id;
private String firstname;
private String lastName;
private String department;
//Setters and Getters
@Override
public int hashCode[]
{
final int PRIME = 31;
return new HashCodeBuilder[getId[]%2==0?getId[]+1:getId[], PRIME].toHashCode[];
}
@Override
public boolean equals[Object o] {
if [o == null]
return false;
if [o == this]
return true;
if [o.getClass[] != getClass[]]
return false;
Employee e = [Employee] o;
return new EqualsBuilder[].
append[getId[], e.getId[]].
isEquals[];
}
}
4. Generating hashCode[] and equals[] in Eclipse IDE
Most editors provide common source code templates. For example, Eclipse IDE has an option to generate an excellent implementation of hashCode[]
and equals[]
.
Right click on Java file -> Source -> Generate hashCode[] and equals[] …
5. Best Practices
- Always use the same fields to generate
hashCode[]
andequals[]
. As in our case, we have used employee
8.public class EqualsTest { public static void main[String[] args] { Employee e1 = new Employee[]; Employee e2 = new Employee[]; e1.setId[100]; e2.setId[100]; System.out.println[e1.equals[e2]]; //false } }
- The
equals[]
must be consistent [if the objects are not modified, then it must keep returning the same value]. - Whenever a.equals[b], then a.hashCode[] must be same as b.hashCode[].
- If we override one method, then we should override the other method as well.
6. Special Attention When Using in ORM
If you’re dealing with an ORM, make sure always to use getters and never use the field references in hashCode[]
and equals[]
. Because in ORM, occasionally fields are lazy loaded and not available until we call their getter methods.
For example, In our
public class EqualsTest {
public static void main[String[] args] {
Employee e1 = new Employee[];
Employee e2 = new Employee[];
e1.setId[100];
e2.setId[100];
System.out.println[e1.equals[e2]]; //false
}
}
5 class if we use @Override
public int hashCode[]
{
final int PRIME = 31;
int result = 1;
result = PRIME * result + getId[];
return result;
}
2. It is very much possible that public class EqualsTest {
public static void main[String[] args] {
Employee e1 = new Employee[];
Employee e2 = new Employee[];
e1.setId[100];
e2.setId[100];
System.out.println[e1.equals[e2]]; //false
}
}
8 field is lazy-loaded. So, in this case, id field inside the methods might be zero or @Override
public int hashCode[]
{
final int PRIME = 31;
int result = 1;
result = PRIME * result + getId[];
return result;
}
4, and thus resulting in incorrect behavior.But if uses
@Override
public int hashCode[]
{
final int PRIME = 31;
int result = 1;
result = PRIME * result + getId[];
return result;
}
5, we can be sure even if the field is lazy-loaded, calling the field getter will populate the field first.If you feel I am missing something or wrong somewhere, please leave a comment. I will update this post again to help others.