How to implement equals() and hashcode() methods in Java ?
1) Implementing equals() method
In Java if you want to check that two objects are meaningfully equal, then you need to implement equals()
method in the respective Class. This is useful when you put objects in a Set
or a Map
implementation where you want to identify the unique object, as these classes rely on equals()
method to uniquely identify an object.
By default the equals()
implementation in Object class uses ==
operator to compare two objects which is comparing by references.
Suppose you have a Class Color and it has one attribute String color. Now you have two instances of Color Class which both have color as blue. So these two instances are meaningfully equal, but to compare you need to implement equals method in Color class.
Below example shows how to implement equals()
method.
It is good practice to do instanceof
check as shown below, else you may get ClassCastException
while casting the object.
The equals()
method follows below:
- Reflexive: If a reference x is not null, then
x.equals(x)
must return true. - Symmetric: If references x,y are not null, then
x.equals(y)
should return true if and only ify.equals(x)
returns true. - Transitive: If references x,y,z are not null, and if
x.equals(y)
&y.equals(z)
return true thenx.equals(z)
must return true. - Consistent: If references x,y are not null, then multiple invocations of
x.equals(y)
must return true consistently or false consistently. - If a reference x is not null, then
x.equals(null)
must return false.
public class Color { private String color; public Color(String color) { this.color = color; } public String getColor() { return this.color; } @Override public boolean equals(Object obj) { if (obj instanceof Color) { Color other = (Color) obj; if (other.color.equals(this.color)) { return true; } } return false; } public static void main(String args[]) { Color c1 = new Color("blue"); Color c2 = new Color("blue"); System.out.println(c1.equals(c2)); // prints true } }
2) Implementing hashCode() method
When you use data structure like HashMap
, apart from implementing equals()
method, you also need to implement hashCode()
to properly distribute the keys in HashMap
.
HashMap
uses buckets to store keys, and to uniformly distribute keys across buckets, it uses hashCode()
to decide in which bucket key will land up.
A bucket may contain more then one key with same hashCode value but equals()
method will determine which is the correct key. So if two objects are equal, they should always have same hashcode but the reverse is not mandatory.
Below example shows how to implement equals()
and hashCode()
methods. Here we create a MobileNumber class and to determine if two mobile numbers are equal, we use prefix and the mobileNumber attributes.
Note that in hashCode()
implementation, we multiply intermediate values by a prime number so that its evenly generated.
// Overrides equals and hashcode in Java public final class MobileNumber { private final int prefix; private final int mobileNumber; public MobileNumber(int prefix, int mobileNumber) { this.prefix = prefix; this.mobileNumber = mobileNumber; } // equals method implementation @Override public boolean equals(Object o) { if (o == this) { return true; } if ( !(o instanceof MobileNumber) ) { // checks for null also return false; } MobileNumber mn = (MobileNumber) o; return (mn.mobileNumber == mobileNumber && mn.prefix == prefix); } // hashCode method implementation @Override public int hashCode() { int result = 17; result = 31 * result + prefix; result = 31 * result + mobileNumber; return result; } // Test public static void main(String[] args) { MobileNumber mobileNumber1 = new MobileNumber(91, 1234565789); MobileNumber mobileNumber2 = new MobileNumber(92, 1234565789); System.out.println(mobileNumber1.equals(mobileNumber2)); MobileNumber mobileNumber3 = new MobileNumber(91, 1234565789); System.out.println(mobileNumber1.equals(mobileNumber3)); } }
Output :
false true
3) Implement equals() and hashcode() using Java 7 Objects equals() & hashcode().
Java Objects
class also provides equals() & hashcode() methods to simplify the implementation as shown below.
It makes equals() & hashcode() implementations more compact.
Objects equals() method will return true if both the arguments are equal while hashcode() will return a hashcode if argument is not null.
import java.util.Objects; public final class MobileNumber { private final int prefix; private final int mobileNumber; public MobileNumber(int prefix, int mobileNumber) { this.prefix = prefix; this.mobileNumber = mobileNumber; } // equals method implementation @Override public boolean equals(Object o) { if (o == null) { return false; } if ( getClass() != o.getClass() ) { return false; } MobileNumber mn = (MobileNumber) o; return (Objects.equals(this.prefix, mn.prefix) && Objects.equals(this.mobileNumber, mn.mobileNumber)); } // hashCode method implementation @Override public int hashCode() { return Objects.hash(this.prefix, this.mobileNumber); } // Test public static void main(String[] args) { MobileNumber mobileNumber1 = new MobileNumber(91, 1234565789); MobileNumber mobileNumber2 = new MobileNumber(92, 1234565789); System.out.println(mobileNumber1.equals(mobileNumber2)); MobileNumber mobileNumber3 = new MobileNumber(91, 1234565789); System.out.println(mobileNumber1.equals(mobileNumber3)); } }
Output :
false true
4) Using Apache Commons Lang EqualsBuilder and HashCodeBuilder method.
You can also use Apache commons lang library to implement equals() and hashcode() methods. You can specify the Class attribute (you want to use in implementing equals and hashcode) in the EqualsBuilder
or HashCodeBuilder
append method.
<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.7</version> </dependency>
import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder; public final class MobileNumber { private final int prefix; private final int mobileNumber; public MobileNumber(int prefix, int mobileNumber) { this.prefix = prefix; this.mobileNumber = mobileNumber; } // equals method implementation @Override public boolean equals(Object o) { if (o == null) { return false; } if ( getClass() != o.getClass() ) { return false; } MobileNumber mn = (MobileNumber) o; return new EqualsBuilder() .append(prefix, mn.prefix) .append(mobileNumber, mn.mobileNumber) .isEquals(); } // hashCode method implementation @Override public int hashCode() { return new HashCodeBuilder(17, 31) .append(this.prefix) .append(this.mobileNumber) .toHashCode(); } // Test public static void main(String[] args) { MobileNumber mobileNumber1 = new MobileNumber(91, 1234565789); MobileNumber mobileNumber2 = new MobileNumber(92, 1234565789); System.out.println(mobileNumber1.equals(mobileNumber2)); MobileNumber mobileNumber3 = new MobileNumber(91, 1234565789); System.out.println(mobileNumber1.equals(mobileNumber3)); } }
Output :
false true
References :
https://docs.oracle.com/javase/8/docs/api/java/util/Objects.html#equals-java.lang.Object-
https://docs.oracle.com/javase/8/docs/api/java/util/Objects.html#hashCode-java.lang.Object-