Wednesday, February 23, 2011

Overriding equals() and hashCode() method in Java and Hibernate - Example, Tips and Best Practices

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 and Hibernate 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 along-with 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 behaviour, contract of equals and hasCode method and properties of equals method in Java on different circumstances. You can also JUnit4 annotation to write JUnit test cases, 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.

6) Don't use instanceof check in equals method, as it could break contract of equals() method in sub-class, results in non-symmetric equals, because instanceof return true for child class as well. For example, if you compare two objects Parent and Child from same type-hierarchy; Parent.equals(child) will return true, because child instanceof Parent is true, but Child.equals(parent) will return false, because Parent instanceof Child is false. This means equals() is not following symmetric contract, which states if a.equals(b) == true than b.equals(a) == true, as shown below :

public class Parent {
}

public class Child extends Parent {
}

public class InstanceOfCheck {

    public static void main(String args[]) {

        Parent p = new Parent();
        Child c = new Child();

        System.out.println("child instanceof Parent " + (c instanceof Parent));
        System.out.println("parent instanceof Child " + (p instanceof Child));

    }

}

Output :
child instanceof Parent true
parent instanceof Child false

Alternatively, you can mark equals as final method to prevent it from being overridden.

7) While comparing String object in Java, prefer equals() than == operator.

8) Use IDE or Apache commons EqualsBuilder and HashCodeBuilder utility classes to automatically implement equals() and hashcode() method in Java.

9) Two object which is logically equal but loaded from different ClassLoader cannot be equals. Remember that getClass() check, it will return false if class loader is different.

10) Use @Override annotation on hashcode() as well, as it also prevents subtle mistakes over return type. e.g. return type of hashcode() method is int, but many times programmers mistakenly put long.

11) One  example, where equals method is not consistent with compareTo is java.math.BigDecimal class. If you compare two BigDecimal object e.g. 120.00 and 120.000, equals method will return false, while compareTo will return zero. Both are inconsistent, because equals take both scale and value in consideration, while compareTo method only consider values. 

12) From Java 7 you can also use a new utility class called java.util.Objects for null safe equality check and calculating hash code. You can replace our null-safe code for check equality :

(name == guest.name || (name != null && name.equals(guest.getName()))) 

to much concise

Objects.equals(name, guest.getName());


Use of Equals and Hashcode Method in Hibernate

Hibernate is a popular, open source Java persistent framework, which provides Object Relational Mapping, also known as ORM framework. It uses equals and hashcode method to provide object's equality in Java side.  You should override equals() and hashcode() if :

1) You are storing instance of persistent class in a Set for representing many-valued associations.

2) You are using reattachment of detached persistent instances.

Another worth noting point is that Hibernate only guarantees equivalence of database row (persistent identity) and Java object inside a particular Session. Which means if you store instances retrieved in different Sessions in a Set, you will be having duplicates. Now the most important aspect of overriding equals and hashcode() for hibernate entity classes, you should never decide equality just based upon identifier. Though it’s convenient to compare identifier to see if the belong to same database row, Unfortunately, we can't use this approach with generated identifiers. Since Hibernate only assign identifier values to the object that are persistent, a newly created instance will not have any identifier value. Similarly, if an instance is not persisted, and currently in a Set, saving it to database will assigned an identifier value, which will further change the value of hashcode() method, finally results in breaking the contract of the Set. That's why it's best to implement equals and hashcode in Hibernate using business key equality e.g. an Employee is same if it's name, surname, father's name, department, date of birth is same. Properties which are not prone to change e.g. date of birth are better candidate of business equality than those which is easier to change e.g. address and contact number.

In short, remember these best practices while overriding equals() and hashcode() for Hibernate entity class :

1) Don't let your equals() method only uses identifier values for equivalence check.

2) Implement equals() and hashCode() using real word key that would identify instance in real world.

3) Use Immutable and unique properties of objects for equality.

4) Don't use getClass() to compare object equality because Hibernate uses proxy and this check will always fail. Instead use instanceof operator, it respect proxy because they have IS-A relationship with actual object.

5) Use getter and setter methods to access properties instead of directly accessing the, because hibernate lazily initialize object, when there getProperty() method is called. Using name may return null but getName() may return value from database.


That’s all about overriding equals() and hashcode() methods 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 clear any coding exercise during Java interviews. Writing code for equals and hashcode is very popular programming interview questions now days. For Hibernate persistent class its rather tricky to override equals() and hashCode() because otherwise bad practices turns into best practices because of extensive of proxy. You should not use Eclipse IDE code generator for equals() and hashCode() for hibernate entity class, as they use getClass() to check type equality.


37 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 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...

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.

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.

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!

krishna chaitanya said...

Can any one tel me y prime 31 used above...

Stuart said...

@Krishna, prime 31 is used to create hashCode which is uniformly distributed to avoid collisions in hash based collection classes. Inclusion of prime e.g. 31, 37 or 17 results in more uniformly distributed hashcode.

Anonymous said...

One of the better example, where equals method is not consistent with compareTo is java.math.BigDecimal class. If you compare two BigDecimal object e.g. 120.00 and 120.000, equals method will return false, while compareTo will return zero. Both are inconsistent, because equals take both scale and value in consideration, while compareTo method only consider values.

Baruch Atta said...

This is why Java is 100 time more difficult than any other language. In COBOL, you say IF FIELDA = FIELDB. Done.

A word count on this subject:
Java - 3900 words
COBOL - six words.

The winner? COBOL of course. At least, when you consider that progress means making things simpler, not more complex.

Anonymous said...

I always initialize objects. That way there are no nulls.
public class Person {
private int id = 0;
private String firstName = "";
private String lastName = "";

I consider that the NullPointerException is a FLAW in the Java design. For example, 0 != "" != null - zero is not equal to empty string is not equal to null. But it shouldn't raise an error.

Anonymous said...

Can you please add info about use of equals and hashcode in Hibernate. I mean why it's important to override equals and hashcode for Hiberante entity class, what happens if we don't? and how we can automate this process.

rop said...

Sorry to say, but you are presenting a too complex set of ad-hoc rules, that inevitable will be forgotten, misunderstood, violated and/or abused by different developers in your team, and result in occasional bugs -- I promise you :)

The first principle when defining equals/hashCode for ORM-entities, is to NEVER consider any other attributes than the ID (or UUIDs; see below) keys.

Think about it... why would you want to involve any other attributes?
If the IDs are equals but the entities differ in some OTHER attribute,
it apparently means you are comparing an entity BEFORE some update, to the SAME entity AFTER the update.
That should simply never be done.
If you accidentally do that, debug your code or rethink your design.

So, if we ONLY consider the IDs (or UUIDs), the only tricky case occurs if you compare two entities where BOTH IDs are null.
That means you compare two entities that have just been created, and not yet persisted.

Are such entities equal or not?
Well, to make a long story short:
In this case, you should EITHER use == on the entities themselves (i.e this==other) to determine equality OR go for the UUID solution.
See, for example: http://www.onjava.com/pub/a/onjava/2006/09/13/dont-let-hibernate-steal-your-identity.html?page=1

Also, a beautiful thing, if you ONLY consider attributes ID (or UUID) is that you can use an abstract super-class for all other entities, that only define setter and getter for the key(s), and put the hashCode and equals methods in this super-class, and then you can just forget about this whole headache in all other entity entity-classes. Hooray! :)

Gopi said...

To let you know there’s a handy utility class called EqualsTester available as part of the GSBase JUnit extensions (http://gsbase.sf.net), which helps enormously in verifying that a given class has implemented the delicate contract for equals and hashCode properly, or not. For example, it can verify the contract as specified by java.lang.Object which states that if A.equals(B) is true then B.equals(A) is also true. It can also check that if A.equals(B) is true then A.hashCode() will equals B.hashCode().

Post a Comment