Introduction
Before we go ahead and explore Apache Commons
EqualsBuilder
and HashCodeBuilder
, we must know the relationship between equals
andhashCode
.java.lang.Object
which is the super class of all Java classes has two very important methods defined in it. They are:public boolean equals(Object obj)
public int hashCode()
These two methods are very important when our classes deal with other Java classes such as
Collection
API used for searching, sorting, comparison and eliminate duplicate objects from a set.public boolean equals(Object obj)
This method checks if some other object passed to it as an argument is equal to the object on which this method is invoked. The default implementation of this method in
Object
class simply checks if two object references x
and y
refer to the same object, i.e., it checks if x == y
. This particular comparison is also known as “shallow comparison”. However, the classes providing their own implementations of the equals method are supposed to perform a “deep comparison”.public int hashCode()
This method returns the hash code value for the object on which this method is invoked. This method returns the hash code value as an integer and is supported for the benefit of hashing based collection classes such as
Hashtable
, HashMap
, HashSet
, etc.Relationship between equals and hashCode
Equal objects must produce the same hash code as long as they are equal, however unequal objects need not produce distinct hash codes.
Implementation
While
hashCode()
and equals()
typically impact logic and performance, they are also often more tricky to implement correctly. The most important rule is that when one of these two methods is overridden, the other one should be as well. Because it can be tricky to implement hashCode()
andequals()
correctly, it is helpful to have EqualsBuilder
and HashCodeBuilder
two reusable implementations of these provided as part of Apache Commons Lang builder package.I particularly like the way how
EqualsBuilder
uses reflection to determine if the two Objects are equal or HashCodeBuilder
uses reflection to build a valid hash code. But reflection hits the performance of application, so use it where the performance is not very critical. However these two builders also provide the alternative approach. Let’s demonstrate both approaches one by one:- Using Reflection:Let’s create a simple class called
Employee
as the following mentioned code:Collapsepackage blog.commons; import org.apache.commons.lang.builder.EqualsBuilder; import org.apache.commons.lang.builder.HashCodeBuilder; public class Employee { private int id; private String name; private int deptId; private String designation; public Employee(int id, String name, int deptId, String designation) { this.id = id; this.name = name; this.deptId = deptId; this.designation = designation; } @Override public boolean equals(Object obj) { return EqualsBuilder.reflectionEquals(this, obj); } @Override public int hashCode() { return HashCodeBuilder.reflectionHashCode(this); } }
Now create aMain
class to check how it works:Collapsepackage blog.commons; import java.util.Arrays; import java.util.HashSet; import java.util.Set; public class Main { public static void main(String[] args) { Employee emp1 = new Employee(1, "Allen", 12, "Accountant"); Employee emp2 = new Employee(1, "Allen", 13, "Accountant"); System.out.println ("Is emp1 equals to emp2: " + emp1.equals(emp2)); Set<Employee> employees = new HashSet<Employee>(); employees.addAll(Arrays.asList(emp1,emp2)); System.out.println("Size of set: " + employees.size()); } }
If you execute themain
method, the output will be as follows:CollapseIs emp1 equals to emp2: false Size of set: 2
Here you can see that the employee “Allen
” whose employee Id is “1
? is an “Accountant
” does his book keeping job for two different departments which department ids are12
and13
respectively. But the objectemp1
andemp2
are treated as two different persons.Now, let’s exclude thedeptId
field to determine equality and buildhashCode
and see the effect. For doing this, you need to slightly modify the code ofEmployee
class:Collapsepackage blog.commons; import org.apache.commons.lang.builder.EqualsBuilder; import org.apache.commons.lang.builder.HashCodeBuilder; public class Employee { private int id; private String name; private int deptId; private String designation; public Employee(int id, String name, int deptId, String designation) { this.id = id; this.name = name; this.deptId = deptId; this.designation = designation; } @Override public boolean equals(Object obj) { return EqualsBuilder.reflectionEquals (this, obj,new String[] {"deptId"}); } @Override public int hashCode() { return HashCodeBuilder.reflectionHashCode (this,new String[] {"deptId"}); } }
Again, execute the samemain
method to see the output:CollapseIs emp1 equals to emp2: true Size of set: 1
Here, as you can see, nowemp1
andemp2
are treated as equal butemp1
are been replaced byemp2
, hence the size of the set employees is one. To overcome this problem, do not exclude thedeptId
while generatinghashCode
. YourhashCode
method should look like the following:Collapse@Override public int hashCode() { return HashCodeBuilder.reflectionHashCode(this); }
Now the output should be shown as below if you execute themain
method again:CollapseIs emp1 equals to emp2: true Size of set: 2
- Without Using Reflection:In my previous examples, you have seen how easily and in a fascinating manner we can use reflection capability of
EqualsBuilder
andHashCodeBuilder
to overrideequals
andhashCode
methods. Now, I am going to show you how can you achieve the same output without using reflection which helps to improve performance:Collapsepackage blog.commons; import org.apache.commons.lang.builder.EqualsBuilder; import org.apache.commons.lang.builder.HashCodeBuilder; public class Employee { private int id; private String name; private int deptId; private String designation; public Employee(int id, String name, int deptId, String designation) { this.id = id; this.name = name; this.deptId = deptId; this.designation = designation; } @Override public boolean equals(Object obj) { if (obj instanceof Employee == false) { return false; } if (this == obj) { return true; } Employee other = (Employee) obj; return new EqualsBuilder().append(this.id , other.id) .append(this.name , other.name) .append(this.designation , other.designation).isEquals(); } @Override public int hashCode() { return new HashCodeBuilder().append(this.id) .append(this.name) .append(this.deptId) .append(this.designation) .hashCode(); } }
If you run themain
method this time, you get similar output as it has been shown in the last output result. Just notice here that I am not appendingdeptId
inEqualsBuilder
but I am doing it while generatinghashCode
.
Like these
EqualsBuilder
and HashCodeBuilder
Apache Commons project provides many such reusable APIs to speed up your application development time. You can find more information regarding Apache Commons from the following link:
No comments:
Post a Comment