Monday, 14 July 2014

An Example of Overriding Equals, HashCode and CompareTo method in Java

Though modern IDE like Eclipse, IntelliJ or Netbeans allows you to generate equals, hashCode and compareTo methods for your value classes, it's equally important, you know how to do that by hand. Byoverriding equals and hashcode method by yourself, you know how they work, what kind of errors you can get, and most importantly, it's expected form you, as a Java programmer in any core Java interview. More often, you would see a coding question in Java, which ask you to override equals(),hashcode()compare() and compareTo() methods for a value class. Since I have already shared some tips on How to override compareTo method in Java, and couple of example of writing your own comparator in Java, here I am sharing another simple example of overriding equals and hashCode methods. If you know rules of overriding equals and hashCode, you might know that, whenever you override equals, you must have to override hashCode, otherwise your object will not behave properly on various collection classes e.g. Map or Set, which uses equalscompareTohashCode to implement there invariants e.g. Set implementations should not allow any duplicates.


Overriding Equals, HashCode and CompareTo in Java

Example of overriding equals hashcode and compareTo in JavaIn this Java program, we will override all three method for a Person class, which contains a String name, aninteger id and a Date for date of birth. In order to override equals, you need to follow certain checks, e.g. checking null, checking type of object etc, Also your equals() method, when compared with null, should return false instead of throwing NullPointerException. See this post for detailed tips on overriding equals method in Java. For overriding hashCode, you need to choose a prime, usually 31, but you can also choose other prime numbers e.g. 37, 17 etc. The reason for choosing these prime numbers are to generate a uniquely distributed hashcode, which eventually helps to avoid collision, when used in hash based collections like Hashtable and HashMap. Another worth noting thing is using all variables, used in equals, in hashCode method to keep equals and hashCode consistent, and adhere to rules of overriding hashCode in Java. I have already discussed about Comparable and compareTo method, while sorting list of objects in Java. A simple implementation ofcompareTo must return negative number if current object is lesser than provided object, positive if current object is greater in order than provided and zero if both objects are equal. Another worth noting point is that, compareTo() and equals() must be consistent with each other, otherwise your object will not behave properly on Collection classes, which uses compareTo() for sorting e.g.TreeSet or TreeMap. Anyway, here is a simple example of overriding equals, hashcode and compareTo in Java.

Sample implementation of Equals, HashCode and CompareTo in Java

In this sample example of overriding equals, hashcode and compareTo method, we will use a class named Person which has 3 properties String name, integer id and Date to represent date of birth.  We will also use Generics along with Comparable to provide a type safe implementation.

/**
 * Simple Java Class to represent Person with name, id and date of birth.
 *
 * @author Javin Paul
 */
public class Person implements Comparable<Person>{
   private String name;
   private int id;
   private Date dob;

    public Person(String name, int id, Date dob) {
        this.name = name;
        this.id = id;
        this.dob = dob;
    }
  
   @Override
   public boolean equals(Object other){
       if(this == other) return true;
      
       if(other == null || (this.getClass() != other.getClass())){
           return false;
       }
      
       Person guest = (Person) other;
       return (this.id == guest.id) &&
              (this.name != null && name.equals(guest.name)) &&
              (this.dob != null && dob.equals(guest.dob));
   }
  
    @Override
   public int hashCode(){
       int result = 0;
       result = 31*result + id;
       result = 31*result + (name !=null ? name.hashCode() : 0);
       result = 31*result + (dob  !=null ? dob.hashCode() : 0);
      
       return result;
   }

    @Override
    public int compareTo(Person o) {
        return this.id - o.id;
    }   
}

Sample JUnit test case for testing Equals and HashCode

Here is simplest of simple test case to verify equals and hashCode in Java. Remember this unit test are not enough, if you want to verify all properties of equals and hashCode, see unit test for equals method in Java.
import java.util.Date;
import org.junit.Test;
import static org.junit.Assert.*;

/**
 * Simple example of using equals and hashCode method
 * @author Javin Paul
 */
public class EqualsAndHashCodeTest {   

  
   @Test
   public void testEquals(){
       Person james = new Person("James", 21, new Date(1980,12, 1));
       Person same = new Person("James", 21, new Date(1980,12, 1));
       Person similar = new Person("Harry", 21, new Date(1981,12,1));
      
       assertTrue(james.equals(same));
       assertTrue(james.hashCode() == same.hashCode());
    
       assertFalse(james.equals(null));
       assertFalse(james.equals(similar));
       assertTrue(james.hashCode() != similar.hashCode());
   } 
  
}


That's all on this simple example of overriding equals, hashcode and compareTo method in Java. As I said, these test are just to verify that equals and hashCode methods are working, you can add more test to verify compareTo, and other behaviors of all three methods.

1 comment:

  1. Best article. Thanks for sharing.
    https://www.flowerbrackets.com/difference-between-equal-operator-vs-equals-method-java/

    ReplyDelete