Saturday, April 26, 2014

Override equals and hashCode methods in Java

Theory

equals() and hashCode() methods are defined in the Object class. So all Java objects inherit a default implementation of these methods.

The default implementation of the equals() method (javadoc) actually is the same as the “==” operator. It checks to see if both objects reference the same memory location. But, the equals method is meant to compare the contents of 2 objects, and not their location in memory. So when overriding the equals() method, you should compare the values of the objects instead.

The equals() method must be consistent (if the objects are not modified, then it must keep returning the same value).

The hashCode() method (javadoc) must also be consistent (if the object is not modified in terms of equals(), it must keep returning the same value).

The relation between the two methods is:

Whenever a.equals(b), then a.hashCode() and b.hashCode() must produce the same integer result.

The general contract for the hashCode method states that equal objects must have equal hash codes.


Practice

If you override the equals method, then you must override the hashCode method.

Use the same set of the object's attributes (fields) in the equals and hashCode method's code.

Use the EqualsBuilder and HashCodeBuilder helper classses from   Apache Commons Lang.

Below is a usage example:

import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;

public class Employee {
 
   private Integer id;
   private String firstname;
   private String lastname;
   private int age;
   //...

   @Override 
   public int hashCode() {
      // you pick a hard-coded, randomly chosen, non-zero, odd number as args
      // ideally different for each class
      return new HashCodeBuilder(17, 37).
      //use next line only if you want to inherit hashCode behavior from superclass
      //appendSuper(super.hashCode()).
      append(id).
      append(firstname).
      append(lastname).
      toHashCode();
   } 

   @Override
   public boolean equals(Object obj) {
      if (obj == this)
         return true;
      if (obj == null)
         return false; 
      if (obj.getClass() != getClass())
         return false;  
     
      Employee rhs = (Employee) obj;
      return new EqualsBuilder().
      //use next line only if you want to inherit equals behavior from superclass
      //appendSuper(super.equals(obj)).
      append(this.id, rhs.id).
      append(this.firstname, rhs.firstname).
      append(this.lastname, rhs.lastname).
      isEquals();
   }
 
} 



You can also use Eclipse to generate the two methods for you:

Right click on class from editor pane > source > Generate hashCode() and equals()


Note when using in ORM

If you will use the object in ORM, always use getters instead of field references in your hashCode() and equals() methods.  The reason is that when fields are lazy-loaded, the field values are not available until their getter methods are called. In this case, the value may be null and lead to incorrect behavior.



No comments:

Post a Comment