Wednesday, February 23, 2011

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. String overrides 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;

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 NullPointerException during equals check in Java.

Code Example of overriding equals method in Java
equals and hashCode method in Java example tutorialLet’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;
    }
   
}

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.


Other Java fundamental tutorials from Javarevisited Blog
Please share with your friends if like this article

34 comments:

Sourabh Girdhar said...

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.

Anonymous said...

Since firstName and lastName are String objects, == operator might not always return true, you should use equals() method to compare them.

Kevin said...

You'll want to be careful using == on Strings like you're doing, they may not always be the same object.

Javin @ FIX Protocol Tutorial said...

Thanks Sourabh for sharing ToEqualsBuilder , I will check this.

Javin @ FIX Protocol Tutorial said...

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

Cay Horstmann said...

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.

Anonymous said...

Useful info. Thanks

Bibhuti said...

Thanks, it is very help full to compare the object by call equals() method...

Anonymous said...

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.

JItendra Sawant said...

Man.. too good explanations in all ur posts..

Thanks a lot.

Anonymous said...

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.

Ashutosh Agarwal said...

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.

sraban said...

it is really help full for any java programer.
please help for this question
what is the need of jUnit test in equals() method

Javin @ java enum examples said...

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

Enio Pereira said...

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.

Javin @ Java.lang.OutOfMemoryError: Java heap space said...

@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

Anonymous said...

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 ?

Anonymous said...

This is a poorly proofed article whose English is almost so atrocious as to be unreadable. It was difficult to decipher for that reason.

Anonymous said...

I had a question regarding instanceof check :

if((obj == null) || (obj.getClass() != this.getClass()))
{
return false;
}
----
Well, this means if the contended object ie. this is to be added to the collection say HashMap will be added even if there is a type mismatch.
According to me , we must return true because when equals method returns true, we mean to skip that object of different class type from being added to the collection.

Dev J

Anonymous said...

Some people recommend using Equals and HashCodeBuilder from apache commons but that is likely to create ThreadLocal variable and memory leak. Thanks to Tomcat that it points that out as shown in below message:

"SEVERE: The web application [/Helloworld] created a ThreadLocal with key of type [org.apache.commons.lang.builder.HashCodeBuilder$1] (value [org.apache.commons.lang.builder.HashCodeBuilder$1@132b67c]) and a value of type [java.util.HashSet] (value [[]]) but failed to remove it when the web application was stopped. This is very likely to create a memory leak."

Sachin said...

@Anonymous, As per equals and hashcode contract, equals() method should return false if compared with null and also if two object are not of same type than how can they be equal ? By the way HashMap doesn't have that requirement as well, you might be talking about HashSet which doesn't allow duplicates and uses equals() method to check for duplicates. HashSet will allow one null and generics will prevent adding another type. look equals javadoc for equals and hashcode contract.

Umang Bobda said...

Very well explained , superb article.

Manuel said...

Very useful! Thanks a lot!

Sourabh said...

Under Common Errors while overriding equals in Java in Point 2 ; the code should make use of '&&' instead of '&'.So it should read :

firstname == guest.firstname || (firstname != null && firstname.equals(guest.firstname)));

instead of

firstname == guest.firstname || (firstname != null & firstname.equals(guest.firstname)));

Javin Paul @ sort arraylist in Java said...

Hi Saurabh, thanks for pointing that, Its indeed short circuit AND operator && so that if first condition is not true don't all equals() method to avoid NullPointerException

Anonymous said...

Java 7 users can use

java.util.Objects.equals(firstName, guest.firstName)

and

Objects.hashCode(firstName)

(nulls are handled automatically :)

Unknown said...

Useful 4 test helper classes for equals hashcode are here https://github.com/chas66/jUnit-Paramterized-test
For junit3 can use the junit-Addons project on sourceforge

Anonymous said...

Best tutorial on equals and hashCode I have read so far. equals() and hashCode() example are very clear to me. Just to add :

1) Two object which is logically equal but loaded from different ClassLoader can not be equals.

2) Use EqulasBuilder and HashCodeBuilder from Apache commons for overriding equals and hashCode.

Anonymous said...

Thank you, thank you, THANK YOU for this informative tutorial! I am taking a programming languages class and am pretty much expected to already know Java, which I don't. This is incredibly helpful!

Anonymous said...

In one of Interview, one questions appeared How equals method works in Java and explains this with example of String class's equals() method. I explained them that equals() is like any other method but called by many Java builtin classes e.g. Collections and you need to override hashcode when you implement equals method, is that correct ?

Gopi said...

@Override annotation on hashCode() method also prevents subtle mistakes over return type. e.g. return type of hashCode method is int, but many times I tried to put long. If you are using IDE like netbeans, it will highlight that this is not overriding actual hashCode method.

Maxim Dmitriev said...

Hello, why didn't you take care of this object? If it is null, a NullPointerException will be thrown.

if (this == null || obj == null || obj.getClass() != this.getClass()) {
return false;
}

Javin @ print array java said...

Hi @Maxim, this can not be null mate, because if this would have been null your call to equals method has thrown NullPointerException already, since you are able to reach inside equals() means this is not null. Let me know if you disagree, and see any edge case, which is worth considering

Maxim Dmitriev said...

Hi, @Javin, I completely understood you. Of course, I forgot that if a variable references to null, none of its methods can be called. Thank you!

Post a Comment