views:

1181

answers:

8

Recently I read through this Developer Works Document. The document is all about defining hashCode() and equals() effectively and correctly, but I am not able to figure out why we need to override these two methods.

How can I take the decision to implement these method efficiently?

+1  A: 

Because if you do not override them you will be use the default implentation in Object.

Given that instance equality and hascode values generally require knowledge of what makes up an object they generally will need to be redefined in your class to have any tangible meaning.

Visage
A: 

Assume you have class (A) that aggregates two other (B) (C), and you need to store instances of (A) inside hashtable. Default implementation only allows distinguishing of instances, but not by (B) and (C). So two instances of A could be equal, but default wouldn't allow you to compare them in correct way.

Dewfy
A: 

It is useful when using Value Objects. The following is an excerpt from the Portland Pattern Repository:

Examples of value objects are things like numbers, dates, monies and strings. Usually, they are small objects which are used quite widely. Their identity is based on their state rather than on their object identity. This way, you can have multiple copies of the same conceptual value object.

So I can have multiple copies of an object that represents the date 16 Jan 1998. Any of these copies will be equal to each other. For a small object such as this, it is often easier to create new ones and move them around rather than rely on a single object to represent the date.

A value object should always override .equals() in Java (or = in Smalltalk). (Remember to override .hashCode() as well.)

Ionuț G. Stan
+5  A: 

You must override hashCode() in every class that overrides equals(). Failure to do so will result in a violation of the general contract for Object.hashCode(), which will prevent your class from functioning properly in conjunction with all hash-based collections, including HashMap, HashSet, and Hashtable.


   from Effective Java, by Joshua Bloch

By defining equals() and hashCode() consistently, you can improve the usability of your classes as keys in hash-based collections. As the API doc for hashCode explains: "This method is supported for the benefit of hashtables such as those provided by java.util.Hashtable."

The best answer to your question about how to implement these methods efficiently is suggesting you to read Chapter 3 of Effective Java.

JuanZe
A: 

Both the methods are defined in Object class. And both are in its simplest implementation. So when you need you want add some more implementation to these methods then you have override in your class.

For Ex: eqauls() method in object only checks its equality on the reference. So if you need compare its state as well then you can override that as it is done in String class.

GK
+1  A: 

Joshua Bloch said it better than me in Effective Java, so just take a look at it !

Valentin Rocher
A: 

Simply put, the equals-method in Object check for reference equality, where as two instances of your class could still be semantically equal when the properties are equal. Example of this

crunchdog
+1  A: 

It is not always necessary to override hashcode and equals. But if you think you need to override one, then you need to override both of them. Let's analyze what whould happen if we override one but not the other and we attempt to use a Map.

Say we have a class like this and that two objects of MyClass are equal if their importantField is equal (with hashCode and equals generated by eclipse)

public class MyClass {

    private final String importantField;
    private final String anotherField;

    public MyClass(final String equalField, final String anotherField) {
        this.importantField = equalField;
        this.anotherField = anotherField;
    }

    public String getEqualField() {
        return importantField;
    }

    public String getAnotherField() {
        return anotherField;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result
                + ((importantField == null) ? 0 : importantField.hashCode());
        return result;
    }

    @Override
    public boolean equals(final Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        final MyClass other = (MyClass) obj;
        if (importantField == null) {
            if (other.importantField != null)
                return false;
        } else if (!importantField.equals(other.importantField))
            return false;
        return true;
    }

}

Override only hashCode

Imagine you have this

MyClass first = new MyClass("a","first");
MyClass second = new MyClass("a","second");

If you only override hashCode then when you call myMap.put(first,someValue) it takes first, calculates its hashCode and stores it in a given bucket. Then when you call myMap.put(first,someOtherValue) it should replace first with second as per the Map Documentation because they are equal (according to our definition).

But the problem is that equals was not redefined, so when the map hashes second and iterates through the bucket looking if there is an object k such that second.equals(k) is true it won't find any as second.equals(first) will be false.

Override only equals

If only equals is overriden, then when you call myMap.put(first,someValue) first will hash to some bucket and when you call myMap.put(first,someOtherValue) it will hash to some other bucket. So, although they are equal, as they don't hash to the same bucket (different hashCode) the map can't realize it and both of them stay in the map.

Hope it was clear

Lombo