36

Ok, I have heard from many places and sources that whenever I override the equals() method, I need to override the hashCode() method as well. But consider the following piece of code

package test;

public class MyCustomObject {

    int intVal1;
    int intVal2;

    public MyCustomObject(int val1, int val2){
        intVal1 = val1;
        intVal2 = val2;
    }

    public boolean equals(Object obj){
        return (((MyCustomObject)obj).intVal1 == this.intVal1) && 
                (((MyCustomObject)obj).intVal2 == this.intVal2);
    }

    public static void main(String a[]){
        MyCustomObject m1 = new MyCustomObject(3,5);
        MyCustomObject m2 = new MyCustomObject(3,5);
        MyCustomObject m3 = new MyCustomObject(4,5);

        System.out.println(m1.equals(m2));
        System.out.println(m1.equals(m3));
    }
}

Here the output is true, false exactly the way I want it to be and I dont care of overriding the hashCode() method at all. This means that hashCode() overriding is an option rather being a mandatory one as everyone says.

I want a second confirmation.

bragboy
  • 34,892
  • 30
  • 114
  • 171
  • possible duplicate of http://stackoverflow.com/questions/371328/why-is-it-important-to-override-gethashcode-when-equals-method-is-overriden-in-c – Oded Apr 25 '10 at 07:56
  • 6
    Not a dupe of that one; that's C#, this is Java. (The issue is very similar, maybe identical, but still.) – Thomas Apr 25 '10 at 08:24

5 Answers5

34

It works for you because your code does not use any functionality (HashMap, HashTable) which needs the hashCode() API.

However, you don't know whether your class (presumably not written as a one-off) will be later called in a code that does indeed use its objects as hash key, in which case things will be affected.

As per the documentation for Object class:

The general contract of hashCode is:

  • Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application.

  • If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.

DVK
  • 126,886
  • 32
  • 213
  • 327
  • 1
    And optionally, `hashCode` must do its best not to return the same integer on many values that are likely to occur together during the same execution of the program. I once had a performance bug that it took me a long time to trace to using physical equality along with the default (structural) hash function. This use satisfies the conditions above, but all structurally identical, physically different values were hashed to the same bucket. – Pascal Cuoq Apr 25 '10 at 08:30
  • @Pascal - that is correct. Indeed the document continues: * It is not required that if two objects are unequal according to the equals(java.lang.Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results. **However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hashtables**. – DVK Apr 25 '10 at 10:45
  • "... As much as is reasonably practical, the hashCode method defined by class Object does return distinct integers for distinct objects. (This is typically implemented by converting the internal address of the object into an integer, but this implementation technique is not required by the Java programming language.) " – DVK Apr 25 '10 at 10:45
11

Because HashMap/Hashtable will lookup object by hashCode() first.

If they are not the same, hashmap will assert object are not the same and return not exists in the map.

Dennis C
  • 24,511
  • 12
  • 71
  • 99
6

The reason why you need to @Override neither or both, is because of the way they interrelate with the rest of the API.

You'll find that if you put m1 into a HashSet<MyCustomObject>, then it doesn't contains(m2). This is inconsistent behavior and can cause a lot of bugs and chaos.

The Java library has tons of functionalities. In order to make them work for you, you need to play by the rules, and making sure that equals and hashCode are consistent is one of the most important ones.

polygenelubricants
  • 376,812
  • 128
  • 561
  • 623
4

Most of the other comments already gave you the answer: you need to do it because there are collections (ie: HashSet, HashMap) that uses hashCode as an optimization to "index" object instances, an those optimizations expects that if: a.equals(b) ==> a.hashCode() == b.hashCode() (NOTE that the inverse doesn't hold).

But as an additional information you can do this exercise:

class Box {
     private String value;
     /* some boring setters and getters for value */
     public int hashCode() { return value.hashCode(); }
     public boolean equals(Object obj) { 
           if (obj != null && getClass().equals(obj.getClass()) { 
               return ((Box) obj).value.equals(value); 
            } else { return false; }
     }
}

The do this:

Set<Box> s = new HashSet<Box>();
Box b = new Box();
b.setValue("hello");
s.add(b);
s.contains(b); // TRUE
b.setValue("other");
s.contains(b); // FALSE
s.iterator().next() == b // TRUE!!! b is in s but contains(b) returns false

What you learn from this example is that implementing equals or hashCode with properties that can be changed (mutable) is a really bad idea.

Diego
  • 4,353
  • 1
  • 24
  • 22
0

It is primarily important when searching for an object using its hashCode() value in a collection (i.e. HashMap, HashSet, etc.). Each object returns a different hashCode() value therefore you must override this method to consistently generate a hashCode value based on the state of the object to help the Collections algorithm locate values on the hash table.

Almar
  • 1