How to override equals and hashCode method in Java - Example, Tips
Override equals and hashCode in Java
Equals and hashCode in Java are two fundamental method which is declared in Object class and part or core Java library. equals() method is used to
compare Objects for equality while hashCode is used to generate an integer code corresponding to that object.
equals and hashCode has used extensively in Java core library like they are used while inserting and retrieving Object in HashMap, see
how HashMap works in Java for full story, equals method is also used to avoid duplicates on
HashSet and other Set implementation and every other place where you need to compare Objects. Default implementation of equals() class provided by java.lang.Object compares memory location and only return true if two reference variable are pointing to same memory location i.e. essentially they are same object. Java recommends to override equals and hashCode method if equality is going to be define by logical way or via some business logic and many classes in Java standard library does override it e.g.
Stringoverrides equals, whose implementation of equals() method return true if content of two String objects are exactly same.
Integer wrapper class overrides equals to perform numerical comparison etc.
Since
HashMap and Hashtable in Java relies on equals() and hashCode() method for comparing keys and values, Java provides following rules to override equals method Java. As per following rule equals method in Java should be:
1)
Reflexive : Object must be equal to itself.
2)
Symmetric : if a.equals(b) is true then b.equals(a) must be true.
3)
Transitive : if a.equals(b) is true and b.equals(c) is true then c.equals(a) must be true.
4)
Consistent : multiple invocation of equals() method must result same value until any of properties are modified. So if two objects are equals in Java they will remain equals until any of there property is modified.
5)
Null comparison : comparing any object to null must be false and should not result in NullPointerException. For example a.equals(null) must be false, passing unknown object, which could be null, to equals in Java is is actually a Java coding
best practice to avoid NullPointerException in Java.
Equals and hashCode contract in Java
And equals method in Java must follow its contract with hashCode method in Java as stated below.
1) If two objects are equal by equals() method then there hashcode must be same.
2) If two objects are not equal by equals() method then there hashcode could be same or different.
So this was the basic theory about equals method in Java now we are going to discuss the approach on
how to override equals() method, yes I know you all know this stuff :) but I have seen some of equals() code which can be improved by following correct approach. For illustration purpose we will see an example of Person class and discuss
How to write equals() method in Java for that
class.
Steps to Override equals method in Java
Here is my approach for overriding equals method in Java. This is based on standard approach most of Java programmer follows while writing equals method in Java.
1) Do
this check -- if yes then return true.
2) Do null check -- if yes then return false.
3) Do the instanceof check, if instanceof return false than return false from equals in Java , after some research I found that instead of instanceof we can use getClass() method for type identification because instanceof check returns true for subclass also, so its not strictly equals comparison until required by business logic. But instanceof check is fine if your class is
immutable and no one is going to sub class it. For example we can replace instanceof check by below code
if
((obj ==
null
) ||
(obj.
getClass
()
!=
this.
getClass
()))
return false ;
return false ;
4) Type cast the object; note the sequence instanceof check must be prior to casting object.
5) Compare individual attribute starting with numeric attribute because comparing numeric attribute is fast and use short circuit operator for combining checks. If first field does not match, don't try to match rest of attribute and return false. It’s also worth to remember doing null check on individual attribute before calling equals() method on them recursively to
avoid NullPointerExceptionduring equals check in Java.
Code Example of overriding equals method in Java
Let’s see a code example based on my approach of overriding equals method in Java as discussed in above paragraph and hashCode method is generated by Eclipse IDE, see my post
5 tips to override hashCode in Java for detailed example and explanation of overriding hashCode.
/**
* Person class with equals and hashcode implementation in Java
* @author Javin Paul
*/
public class Person {
private int id ;
private String firstName ;
private String lastName ;
public int getId () { return id ; }
public void setId ( int id ) { this. id = id ; }
public String getFirstName () { return firstName ; }
public void setFirstName ( String firstName ) { this. firstName = firstName ; }
public String getLastName () { return lastName ; }
public void setLastName ( String lastName ) { this. lastName = lastName ; }
@ Override
public boolean equals ( Object obj ) {
if (obj == this ) {
return true ;
}
if (obj == null || obj. getClass () != this. getClass ()) {
return false ;
}
Person guest = (Person ) obj ;
return id == guest. id
&& (firstName == guest. firstName
|| (firstName != null && firstName. equals (guest. getFirstName ())))
&& (lastName == guest. lastName
|| (lastName != null && lastName . equals (guest. getLastName ()))) ;
}
@ Override
public int hashCode () {
final int prime = 31 ;
int result = 1 ;
result = prime * result
+ ((firstName == null ) ? 0 : firstName. hashCode ()) ;
result = prime * result + id ;
result = prime * result
+ ((lastName == null ) ? 0 : lastName. hashCode ()) ;
return result ;
}
}
* Person class with equals and hashcode implementation in Java
* @author Javin Paul
*/
public class Person {
private int id ;
private String firstName ;
private String lastName ;
public int getId () { return id ; }
public void setId ( int id ) { this. id = id ; }
public String getFirstName () { return firstName ; }
public void setFirstName ( String firstName ) { this. firstName = firstName ; }
public String getLastName () { return lastName ; }
public void setLastName ( String lastName ) { this. lastName = lastName ; }
@ Override
public boolean equals ( Object obj ) {
if (obj == this ) {
return true ;
}
if (obj == null || obj. getClass () != this. getClass ()) {
return false ;
}
Person guest = (Person ) obj ;
return id == guest. id
&& (firstName == guest. firstName
|| (firstName != null && firstName. equals (guest. getFirstName ())))
&& (lastName == guest. lastName
|| (lastName != null && lastName . equals (guest. getLastName ()))) ;
}
@ Override
public int hashCode () {
final int prime = 31 ;
int result = 1 ;
result = prime * result
+ ((firstName == null ) ? 0 : firstName. hashCode ()) ;
result = prime * result + id ;
result = prime * result
+ ((lastName == null ) ? 0 : lastName. hashCode ()) ;
return result ;
}
}
If you look above method we are first checking for "
this" check which is fastest available check for equals method then we are verifying whether object is null or not and object is of same type or not. only after verifying type of object we are casting it into desired object to avoid any ClassCastException
in Java. Also while comparing individual attribute we are comparing numeric attribute first using short circuit operator to avoid further calculation if its already unequal and doing null check on member attribute to
avoid NullPointerException.
Common Errors while overriding equals in Java
Though equals() and hashcode() method are defined in Object class along with
wait, notify and notifyAll, and one of fundamental part of Java programming I have seen many programmers making mistake while writing equals() method in Java. I recommend all Java programmer who has just started programming to write couple of equals and hashcode method for there domain or value object to get feel of it. Here I am listing some of common mistakes I have observed on various equals method in Java, if you like to learn more about common mistakes in Java programming then see my post
Don’t use float and double for monetary calculation and
Mixing static and non static synchronized method. Now let’s see common mistakes by Java programmers while overriding equals in Java :
1) Instead of overriding equals() method programmer overloaded it.
This is the most common error I have seen while overriding equals method in Java. Syntax of equals method defined in Object class is public boolean equals(Object obj) but many people unintentionally overloads equals method in Java by writing public boolean equals(Person obj), instead of using Object as argument they use there class name. This error is very hard to detect because of
static binding. So if you call this method in your class object it will not only compile but also execute correctly but if you try to put your object in collection e.g. ArrayList and call contains() method which is based on equals() method in Java it will not able to detect your object. So beware of it. This question is also a
frequently asked question in Java interviews as part of
Overloading vs Overriding in Java as how do you prevent this from happening ? Thankfully alongwith
Generics,
Enum,
autoboxing and
varargs Java 5 also introduces @Override annotation which can be used to tell compiler that you are overriding a method and than compiler will be able to detect this error during
compile time. Consistently using @Override annotation is also a best practice in Java.
2) Second mistake I have seen while overriding equals() method is not doing null check for member variables which ultimately results in
NullPointerException in Java
during equals() invocation. For example in above code correct way of calling equals() method of member variable is after doing null check as shown below:
firstname == guest.
firstname ||
(firstname
!=
null
&& firstname.
equals
(guest.
firstname
)))
;
3) Third common mistake is not overriding hashCode method in Java and only overriding equals() method
.You must have to override both equals() and hashCode() method in Java , otherwise your value object will not be able to use as key object in HashMap because working of
HashMap is based on equals() and hashCode to read more see ,
How HashMap works in Java.
4) Last common mistake programmer make while overriding equals() in Java is not keeping equals() and compareTo() method consistent which is a non formal requirement in order to obey
contract of Set to avoid duplicates. SortedSet implementation like TreeSet uses compareTo to compare two objects like String and if compareTo() and equals() will not be consistent than TreeSet will allow duplicates which will break Set contract of not having duplicates. To learn more about this issue see my post
Things to remember while overriding compareTo in Java
Writing JUnit tests for equals method in Java
Its good
coding practice to write JUnit test cases to test your equals and hashCode method. Here is my approach for writing JUnit test case for equals method in Java. I will write test cases to check equals behavior, contract of equals and hasCode method and properties of equals method in Java on different circumstances. You can also
JUnit4 annotation to write JUnit testcases, than you don’t need to use test prefix on test method, just use
@Test annotations.
testReflexive() this method will test reflexive nature of equals() method in Java.
testSymmeteric() this method will verify symmetric nature of equals() in Java.
testNull() this method will verify null comparison and will pass if equals method returns false.
testConsistent() should verify consistent nature of equals method in Java.
testNotEquals() should verify if two object which are not supposed to equals is actually not equal, having negative test cases in test suite is mandatory.
testHashCode() will verify that if two objects are equal by equals() method in Java then there hashcode must be same. This is an important test if you are thinking to use this object as
key in HashMap or Hashtable
5 Tips on writing equals method in Java
Here are some tips to implement equals and
hashCode method in Java, this will help you to do it correctly and with ease:
1) Most of the IDE like NetBeans, Eclipse and IntelliJ IDEA provides support to generate equals() and hashcode() method. In Eclipse do the right click-> source -> generate hashCode() and equals().
2) If your domain class has any unique business key then just comparing that field in equals method would be enough instead of comparing all the fields e.g. in case of our example if "id" is unique for every Person and by just comparing id we can identify whether two Person are equal or not.
3) While
overriding hashCode in Java makes sure you use all fields which have been used in equals method in Java.
4)
String and Wrapper classes like
Integer, Float and
Double override equals method but
StringBuffer doesn’t override it.
5) Whenever possible try to make your fields
immutable by using
final variables in Java, equals method based on immutable fields are much secure than on mutable fields.
That’s about equals and hashCode in Java, I am reiterating this but its imperative for a Java programmer to be able to write equals , hashCode, compareTo method by hand. It is not just useful for learning purpose but to clare any coding exercise during Java interviews. Writing code for equals and hashCode is very popular programming interview questions now days.