How to override equals method in Java
When I started Java I heard that Java is truly object oriented language and everything in Java is an object, later I found that though its not completely true but yes most of things are in Java is represented via OOPS concept. One of them is Introduction of java.lang.Object class and every class in Java extends this class by default. So when I started my blog and writing about my Java experience as Core Java Tutorials I thought lets write something which helps beginners in Java.
Object class holds some very interesting method which is applicable at object level and one of them is equals () which we are going to discuss in this article. equals () method is used to compare the equality of two object. default implementation of equals() class provided by Object class 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 method if equality is going to be define by logical way or via some business logic and some classes in Java standard library does override it e.g. String class whose implementation of equals() method return true if content of two strings are exactly same.This article is in continuation of my previous articles How Classpath works in Java , difference between HashMap and Hashtable in Java , How Garbage collection works in Java and How Synchronization works in Java if you haven’t read already you may find some useful information based on my experience in Java .
Since HashMap and hashtable in Java relies on equals () and hashcode () method for comparing keys and values,
java has provided a contract to follow while overriding equals () method which state that as per Java your equals() method should adhere following rule:
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(ad) 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.
And equals method in Java must follow its commitment with hashcode as stated below.
1) If two objects are equal by equals() method then there hashcode must be same.
2) If two objects are unequal 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 really be improved by following correct. For illustration purpose we will see an example of Person class and discuss How to write equals () method for that class.
Overriding 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 , 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;
4) Type cast the object; note the sequence instanceof check must be prior to casting object.
5) Compare individual attribute start with numeric attribute because comparing numeric attribute is fast and use short circuit operator for combining checks. So 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 NullPointerException during 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:
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.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;} 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()); }
Common Errors while overriding equals in Java
Though equals and hashcode method are defined in Object class 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.
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 overload 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.
2) Second mistake I have seen while overriding equals() method is not doing null check for member variables which ultimately results in NullPointerException 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 mistake I have seen 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 hashmap in based on equals() and hashcode to read more see , How HashMap works in Java
Writing JUnit tests for equals method in Java
Its good practice to write JUnit test cases to test your equals method. Here is my approach for writing JUnit test case for equals method in Java. I will write test cases to check equals behavior on different circumstances:· testReflexive() this method will test reflexive nature of equals() method in Java.
· testSymmeteric() this method will verify symmetric nature of equals() method in Java.
· testNull() this method will verify null comparison and will pass if equals method returns false.
· testConsistent() will verify consistent nature of equals method in Java.
· testNotEquals() will verify if two object which are not supposed to equals is actually not equal
· testHashcode() will verify that if two objects are equal by equals() method in Java then there hashcode must be same.
5 Tips on Equals method in Java
Tip: most of the IDE provides support to generate equals() and hashcode() method
In Eclipse do the right click-> source -> generate hashCode() and equals().
Tip: 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 then by just comparing id we will be able to identify whether two persons are equal or not.
Tip: while overriding hashcode method in Java makes sure you use all fields which have been used while writing equals method in Java.
Tip: String and Wrapper classes in java override equals method but StringBuffer doesn’t override it.
Tip: Whenever possible try to make your fields immutable, equals method based on immutable fields are much secure than equals method based on mutable fields.
18 comments:
Nice Info
Just to add, There are utilities available to write efficient and time saving equals method. One can use ToEqualsBuilder in Apache commons-lang package. It is very easy to implement and does lot of calculation automatically.
Since firstName and lastName are String objects, == operator might not always return true, you should use equals() method to compare them.
You'll want to be careful using == on Strings like you're doing, they may not always be the same object.
Thanks Sourabh for sharing ToEqualsBuilder , I will check this.
Thanks Kevin and Anonymous for pointing that out , it was typo I was meant to call equals() method of String but some how writing "==" which is absolutely not recommended. Thanks for pointing that out, also it does highlight another important consideration of leveraging "equals()" method of standard JDK classes e.g. String
equals has interesting interactions with inheritance. If you use an instanceof test, you will want to declare equals as final. Otherwise, subclasses might override it and you would get non-symmetric equals, which is a no-no. See Core Java or Effective Java for guidance--it's a tricky subject. Or, if you want subclasses to have their own notion of equality, use getClass() == obj.getClass() instead of instanceof.
Useful info. Thanks
Thanks, it is very help full to compare the object by call equals() method...
what I like most in your equals method tutorial is your unit test for testing equals method in java. those are simply great man and I can reuse it to test my equals() method. many thanks to you.
Man.. too good explanations in all ur posts..
Thanks a lot.
fantastic tutorial about equals method in java, but why not you have mentioned about hashcode in java or how to override hashcode method in java ? Since equals and hashcode has to be overridden together to not explaining about hashcode method surprised me.
Hi, Javin Paul,
While overriding hashcode method in Java makes sure you use all fields which have been used while writing equals method in Java.
I believe it is the other way,
While overriding equals method in Java makes sure you use all fields which have been used while writing hashCode method in Java.
This is to ensure that when two objects are equal there hashcode must be equal.
it is really help full for any java programer.
please help for this question
what is the need of jUnit test in equals() method
Hi Sraban, Thanks for you comment and good to fin d that you like this java equals tutorial. questions is just opposite mate, why not ? I prefer to write for my own because I myself have written equals method , you can avoid if you are using IDE to generate equals method or Apache commons EqualsBuilder and hashCodeBuilder because those are already tested. you may also like my article on how to override hashcode in Java
Hi Javin,
very nice blog. Congratulations.
About the item "1) Instead of overriding equals() method programmer overloaded it.", a trick to avoid this issue is always to use the "@Override" annotation.
Your IDE will complain that the new method does not exist in the parent class.
@Enio Pereira, Thanks for your comment but IDE will not complain sometime and may treat it as different method because of different signature.@Override will ensure this check by IDE and compiler.You may also like How to override hashCode in Java
I like how to override equals and hashCode in Java but do you really need to write unit test cases covering equals and hashcode in Java. I see value of having unit testing on equals and hashcode but does it worth ?
This is a poorly proofed article whose English is almost so atrocious as to be unreadable. It was difficult to decipher for that reason.
Post a Comment