Friday, October 3, 2014

Overriding equals and hashcode for a POJO

This is an interesting case of programming where you need to compare two POJO objects. You might need to compare standalone objects or you may need to uniquely identify them in a collection. This can be achieved by overriding equals() and hashCode() methods.



Consider an example below :

public class CarBean {
   
    private String brand;
    private String color;
   
    public CarBean (){
    }
   
    public CarBean (String brand, String color){
        this.brand= brand;
        this.color= color;
    }

    /**
     * @return the brand
     */
    public String getBrand() {
        return brand;
    }

    /**
     * @param the brand to set
     */
    public void setBrand(String brand) {
        this.brand= brand;
    }

    /**
     * @return the color
     */
    public String getColor() {
        return color;
    }

    /**
     * @param the color to set
     */
    public void setColor(String color) {
        this.color= color;
    }
}


The POJO CarBean represents a real world car. It has two parameters, brand and color. Now, suppose you have two car objects as below :

CarBean car1 = new CarBean("Ford","Black");
CarBean car2 = new CarBean("Ford","Black");

Both the objects have same parameter values. But when you compare this using equals, it returns false :

car1.equals(car2); // This returns false

For the equals method of Object class, these are two different objects regardless of its parameter values. To overcome this you need to override the equals() method in CarBean. The implementation can go like below :

    @Override
    public boolean equals(Object o){
        if(o == null)               
            return false;
        if(!(o instanceof CarBean))
            return false;

        CarBean other = (CarBean) o;
        if(this.brand!=null && this.color!=null){
            if(this.brand.equals(other.brand) && this.color.equals(other.color))
                return true;
            else
                return false;
        }else{
                return false;
        }
    }

Here we compare if the brand and color of Object o matches with the brand and color respectively of current object. The null checks make sure we don't throw a NullPointerException when the parameters of current objects are null. (and hence we can't use equals() on them).
Now the same comparison returns true :

car1.equals(car2); // This returns true

This implementation goes fine unless we are going the use them in a collections e.g. HashMap. Consider the example below :

        HashMap<CarBean,String> carMap = new HashMap();
        carMap.put(car1, "This is Rama's car");

        carMap.get(car1); // This returns - "This is Rama's car"
        carMap.get(new CarBean("Ford","Black")); // This returns null

The hashcode generated for car1 would be a random number which is independent of the parameter values. So, when we create a new object of CarBean the hashcode gets changed and it won't find the key in the map. To overcome this, we need to override the hashCode() method of CarBean :

    @Override
    public int hashCode() {
        int hash = 17;
        hash = 31 * hash + this.brand.hashCode();
        hash = 31 * hash + this.color.hashCode();
        return hash;
    }


The hashcode is now generated on the basis of parameter values of the CarBean object. So now, the same code gives proper values:

        carMap.get(car1); // This returns - "This is Rama's car"
        carMap.get(new CarBean("Ford","Black")); // This returns - "This is Rama's car"

 

No comments:

Post a Comment