Override equals and hashCode methods in Java
This post will discuss how to override equals()
and hashCode()
methods in Java.
The general contract for overriding equals
is proposed in item 8 of Josh Bloch’s Effective Java. Ideally equals()
method should satisfy the following conditions. It should be:
Reflexive
: A non-null object should be equal to itself, i.e.,x.equals(x) == true
.Symmetric
: If the first object is equal to a second object, then the second object should be equal to the first object, i.e.,x.equals(y) == true
if and only ify.equals(x) == true
.Transitive
: If the first object is equal to a second object and the second object is equal to a third object, then the first object should be equal to the third object, i.e.,x.equals(y) == true
andy.equals(z) == true
, thenx.equals(z) == true
.Consistent
: Multiple calls to equals (x.equals(y)
ory.equals(x)
) must return the same value at any point of time unless eitherx
ory
is modified.
Item 9 in Josh Bloch’s Effective Java always asks us to override the hashCode()
method if the class overrides equals()
. Otherwise, the class object will not behave properly on hash-based collections like HashMap
, HashSet
, and Hashtable
(see why?). Also, keep in mind that
- If
equals()
returns true for two objects, thenhashCode()
method should also return the same value, i.e., ifa.equals(b) == true
andb.equals(a) == true
, thena.hashCode() == b.hashCode()
. - If
equals()
returns false for two objects, thenhashCode()
method should return different values, i.e., ifa.equals(b) == false
orb.equals(a) == false
, thena.hashCode() != b.hashCode()
.
Now let’s discuss various ways to override the equals()
and hashCode()
methods in Java.
1. Java 6 and less
Here’s the recommended process to compute hashCode manually before Java 7:
1. Initialize hashcode by a nonzero value; ideally, a prime number, say 17.
2. For all relevant fields from the object (which are used in the equals method for equality), compute the hashcode c
by the following rules and append c
into the result using prime multiplier 37 as result = 31 * result + c
.
- For primitive fields, compute
(int)f
for byte, char or short,(f ? 1 : 0)
for a boolean,
(int)(f ^ (f >>> 32))
for a long (>>>
is unsigned right shift operator) andFloat.floatToIntBits(f)
andDouble.doubleToLongBits(f)
, for float and double, respectively. - Recursively invoke hashCode on the field that is an object reference.
- If the field is an array, invoke the
Arrays.hashCode()
method or compute hashCode for each array element by applying the above rules. - If the value of the field is
null
, return 0.
We should always choose a prime number in the hashCode()
method that results in a good hash function that produces unequal hash codes for unequal objects and uniformly distributes all possible hash values across the hash table to avoid a collision.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
class Person { private String name; private int age; private String gender; // Constructor Person(String name, int age, String gender) { this.name = name; this.age = age; this.gender = gender; } @Override public boolean equals(Object ob) { if (ob == this) { return true; } if (ob == null || ob.getClass() != getClass()) { return false; } Person p = (Person) ob; return p.name.equals(name) && p.age == age && p.gender.equals(gender); } @Override public int hashCode() { int result = 17; // 31 is used as it is a prime and also offers better performance as: // 31 * result == (result << 5) - result result = 31 * result + (name == null ? 0 : name.hashCode()); result = 31 * result + age; result = 31 * result + (gender == null ? 0 : gender.hashCode()); return result; } } class Main { // Program to override `equals` and `hashCode` in Java 6 and less public static void main(String[] args) { Person p1 = new Person("John", 20, "Male"); Person p2 = new Person("John", 20, "Male"); Person p3 = new Person("Carol", 16, "Female"); System.out.println(p1.equals(p2)); // true System.out.println(p1.equals(p3)); // false } } |
Output:
true
false
Another option is to place all the input values into an array and calculate the hash of that array using the Arrays.hashCode(Object[]) method, which was introduced in Java 5, as shown below:
1 2 3 4 |
@Override public int hashCode() { return Arrays.hashCode(new Object[] { name, age, gender }); } |
2. Java 7 and above
Java 7 introduced the Objects
class that provides static utility methods for computing the hash code of an object and comparing two objects.
We should prefer this over implementing our own hash function. For objects containing multiple fields, we can use the Objects.hash(…) method that generates a hash code for a sequence of input values, which internally uses the Arrays.hashCode(Object[])
method. For Object equality, we should use Objects.equals(…)
method or Objects.deepEquals(…)
method to check for deep equality.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
import java.util.Arrays; import java.util.Objects; class Person { private String name; private int age; private String gender; // Constructor Person(String name, int age, String gender) { this.name = name; this.age = age; this.gender = gender; } @Override public boolean equals(Object ob) { if (ob == this) { return true; } if (ob == null || ob.getClass() != getClass()) { return false; } Person p = (Person) ob; return Objects.equals(name, p.name) && p.age == age && Objects.equals(gender, p.gender); } @Override public int hashCode() { return Objects.hash(name, age, gender); // This is equivalent to // return Arrays.hashCode(new Object[] { name, age, gender }); } } class Main { // Program to override `equals` and `hashCode` in Java 7 and above public static void main(String[] args) { Person p1 = new Person("John", 20, "Male"); Person p2 = new Person("John", 20, "Male"); Person p3 = new Person("Carol", 16, "Female"); System.out.println(p1.equals(p2)); // true System.out.println(p1.equals(p3)); // false } } |
Output:
true
false
3. Using Guava Library
Guava library provides Objects class that has helper methods Objects.hashCode(…)
and Objects.equal(…)
that works similarly as Java 7 Objects
class. We can use it before Java 7.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
import com.google.common.base.Objects; class Person { private String name; private int age; private String gender; // Constructor Person(String name, int age, String gender) { this.name = name; this.age = age; this.gender = gender; } @Override public boolean equals(Object ob) { if (ob == this) { return true; } if (ob == null || ob.getClass() != getClass()) { return false; } Person p = (Person) ob; return Objects.equal(name, p.name) && Objects.equal(p.age, age) && Objects.equal(gender, p.gender); } @Override public int hashCode() { return Objects.hashCode(name, age, gender); } } class Main { // Program to override `equals` and `hashCode` in Java using Guava public static void main(String[] args) { Person p1 = new Person("John", 20, "Male"); Person p2 = new Person("John", 20, "Male"); Person p3 = new Person("Carol", 16, "Female"); System.out.println(p1.equals(p2)); // true System.out.println(p1.equals(p3)); // false } } |
Output:
true
false
4. Using Apache Commons Lang
Apache Commons Lang library also provides useful helper classes EqualsBuilder and HashCodeBuilder, strictly following the rules laid out in Josh Bloch’s Effective Java.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder; class Person { private String name; private int age; private String gender; // Constructor Person(String name, int age, String gender) { this.name = name; this.age = age; this.gender = gender; } @Override public boolean equals(Object ob) { if (ob == this) { return true; } if (ob == null || ob.getClass() != getClass()) { return false; } if (ob == this) { return true; } if (!(ob instanceof Person)) { return false; } Person p = (Person) ob; return new EqualsBuilder() .append(age, p.age) .append(name, p.name) .append(gender, p.gender) .isEquals(); } @Override public int hashCode() { return new HashCodeBuilder(17, 37) .append(name) .append(age) .append(gender) .toHashCode(); // or use reflection // return HashCodeBuilder.reflectionHashCode(this); } } class Main { // Program to override `equals` and `hashCode` in Java using Apache Commons public static void main(String[] args) { Person p1 = new Person("John", 20, "Male"); Person p2 = new Person("John", 20, "Male"); Person p3 = new Person("Carol", 16, "Female"); System.out.println(p1.equals(p2)); // true System.out.println(p1.equals(p3)); // false } } |
Output:
true
false
5. Using a Java IDE
It is tedious and error-prone to implement equals()
and hashCode()
manually, especially for large POJOs. Most Java IDEs provide the option to auto-generate equal()
and hashCode()
methods, where we can easily skip fields we don’t want to consider for equality and hash code calculation.
For instance, the following code is auto-generated by eclipse using Source > Generate equal() and hashCode():
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
@Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + age; result = prime * result + ((name == null) ? 0 : name.hashCode()); result = prime * result + ((gender == null) ? 0 : gender.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } Person other = (Person) obj; if (age != other.age) { return false; } if (name == null) { if (other.name != null) { return false; } } else if (!name.equals(other.name)) { return false; } if (gender == null) { if (other.gender != null) { return false; } } else if (!gender.equals(other.gender)) { return false; } return true; } |
Similarly, the following code is auto-generated by IntelliJ IDEA using Code > Generate > equal() and hashCode():
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
@Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } Person person = (Person) o; if (age != person.age) { return false; } if (name != null ? !name.equals(person.name) : person.name != null) { return false; } if (gender != null ? !gender.equals(person.gender) : person.gender != null) { return false; } return true; } @Override public int hashCode() { int result = name != null ? name.hashCode() : 0; result = 31 * result + age; result = 31 * result + (gender != null ? gender.hashCode() : 0); return result; } |
Please note that these generated methods are not automatically updated when we change any field in the POJO. So, we might need to regenerate the methods.
That’s all about overriding equals and hashCode methods in Java.
Why do we need to override equals and hashcode methods in Java?
How to use == operator and equals() method correctly in Java
Thanks for reading.
To share your code in the comments, please use our online compiler that supports C, C++, Java, Python, JavaScript, C#, PHP, and many more popular programming languages.
Like us? Refer us to your friends and support our growth. Happy coding :)