526

Recently I read through this Developer Works Document.

The document is all about defining hashCode() and equals() effectively and correctly, however I am not able to figure out why we need to override these two methods.

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

Exploring
  • 2,493
  • 11
  • 56
  • 97
Shashi
  • 12,487
  • 17
  • 65
  • 111
  • 1
    Case Override only equals: two same object will have different hashcode = same objects go in different bucket(duplication). Case Override only hashcode:two same object will have same hashcode = same object go in same bucket(duplication). – VedantK Sep 12 '17 at 09:27
  • The link appears to be dead. Can I obtain the IBM's developer works document? – tahasozgen Jun 18 '21 at 08:42

31 Answers31

694

Joshua Bloch says on Effective Java

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.

Let's try to understand it with an example of what would happen if we override equals() without overriding hashCode() and 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;
    }

    @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;
    }
}

Imagine you have this

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

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(second,someOtherValue) it will hash to some other bucket (as they have a different hashCode). So, although they are equal, as they don't hash to the same bucket, the map can't realize it and both of them stay in the map.


Although it is not necessary to override equals() if we override hashCode(), let's see what would happen in this particular case where we know that two objects of MyClass are equal if their importantField is equal but we do not override equals().

Override only hashCode

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(second,someOtherValue) it should replace first with second as per the Map Documentation because they are equal (according to the business requirement).

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.

Hope it was clear

SebastianWilke
  • 470
  • 1
  • 4
  • 15
Lombo
  • 11,847
  • 2
  • 20
  • 27
  • 7
    can you please elaborate a little more , in second case , why the second object must go in another bucket? – Hussain Akhtar Wahid 'Ghouri' May 05 '14 at 23:31
  • that was the best explanation of **equals and hashcode**. I would suggest it will be more appropriate if u mention in code(in comments) that how you actually want this code to work. – sagar Sep 12 '14 at 05:10
  • 84
    I don't like this answer because it suggests that you can't override hashCode() without overriding equals(), which is simply not true. You say your example code (the "override only hashCode" part) won't work because you *define* your two objects as equal, but - sorry - this definition is only in your head. In your first example you have two un-equal objects with the same hashCode, and that is perfectly legal. So the reason you need to override equals() is not because you have already overridden hashCode(), but because you want to move your "equals" definition from your head to the code. – user2543253 Dec 30 '14 at 15:38
  • I would like to point out that [this code snippet](https://pastebin.com/qp7WxGHy) suggests that the contract for the equals and hashCode methods for the class `MyClass` was not met - `java.lang.AssertionError: Subclass: object is not equal to an instance of a trivial subclass with equal fields`. – Sandeep Chatterjee Aug 27 '15 at 11:20
  • 23
    `if you think you need to override one, then you need to override both of them` is wrong. You need to override `hashCode` if your class overrides `equals` but reverse is not true. – akhil_mittal Oct 17 '15 at 09:00
  • 1
    I agree with akhil. Lombo said "But if you think you need to override one, then you need to override both of them.". This is only true for using the object as a key in the hash based implementations of HashMap, Hashtable and HashSet. You don't necessarily have to implement hashCode if you implement equals() if you want to compare two objects for equality but you are not using that object in any of the above said hash based implementations. – PhantomReference Dec 10 '15 at 04:53
  • The hashcode is same for the below. I have not overridden both the methodsMap mp=new HashMap(); mp.put(1,"Nik"); mp.put(2,"Nik"); System.out.println(mp.get(1).hashCode()); System.out.println(mp.get(2).hashCode()); – niks Feb 09 '16 at 16:58
  • @HussainAkhtarWahid'Ghouri' Thats exactly the point: they **shouldn't** go to separate buckets because they **equal**, but, the **hashcode isn't equal** so they go to separate buckets. – Johnny Apr 04 '16 at 11:43
  • 9
    I think it's totally **ok to override only hashCode()** without overriding equals() as well. It's also whats written in *Effective Java*: https://books.google.fr/books?id=ka2VUBqHiWkC&pg=PA45&lpg=PA45&dq=joshua+bloch+hashcode&source=bl&ots=yXIlKhqZU2&sig=FcMYxMFOsgJvgO2gthTrcInETOA&hl=fr&ei=_i55S7yOOof34gbQ5vnQCg&sa=X&oi=book_result&ct=result#v=onepage&q&f=false – Johnny Apr 04 '16 at 12:59
  • @user2543253 I updated the answer, thanks for the heads up! Took me a year and a half to get it right ;) – Lombo Jul 21 '16 at 19:46
  • But the OP question is "How can I take the decision to implement these method efficiently". I think that needs to be the center-point here. – Tech Enthusiast Nov 09 '16 at 11:34
  • 1
    @Lombo, you say *"Then when you call `myMap.put(second,someOtherValue)` it should replace `first` with `second`"*. Why is that? If you only overrode `hashCode` it means that you inherited `equals` from `Object` in which case `first` will *not* equal `second`. It seems like you've misunderstood something here. – aioobe Nov 27 '16 at 10:12
  • 3
    @PhantomReference, note that only overriding `equals` would violate the contract spelled out in the javadoc of `Object`: *"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."* Sure, not all parts of all contracts are exercised in all code, but still, formally speaking it's a violation and I'd consider it to be a bug waiting to happen. – aioobe Nov 27 '16 at 10:20
  • I think one very important point missing here is, the problem with overriding equals and hashcode is important only if the object is used as key in Java Collections. If they are used as values, it would have no impact. – user2757415 Nov 09 '17 at 17:41
  • Guess I have an `Integer` key. What if I don't override any of these two methods at all. Is that good? – R Dhaval Aug 07 '18 at 08:57
  • As i know.According to the contract of hashCode which difine in java source code that : *
  • If two objects are equal according to the {@code equals(Object)} * method, then calling the {@code hashCode} method on each of * the two objects must produce the same integer result.
  • – linjiejun Jan 26 '19 at 07:20
  • so! why do you say that they are equal but with distinct hashCode at the "Override only equals " – linjiejun Jan 26 '19 at 07:22
  • **@rajeev pani** 's answer is better and more accurate. – Iceberg Oct 23 '20 at 01:38
  • Agree with many comments posted here. "equals() doesn't have to be overridden if hashCode() is. hashCode() can always return the same value, regardless of the object that invoked it. equals() can be true even if it's comparing different objects." - found another ref : https://www.indiabix.com/java-programming/objects-and-collections/discussion-143 – Haripriya Mar 13 '21 at 04:38
  • @Lombo, _"Then when you call myMap.put(second,someOtherValue) it should replace first with second as per the Map Documentation because they are equal (according to the business requirement)"_ Sorry, what business requirement? I can't find this requirement in your answer, and without it there is no reason why first and second (which are not equal according to the equals() method) shouldn't be hashed to different values. – Yariv Jul 01 '21 at 03:46
  • if the store data type is base type, equals compared the value, is it possible do not override hashcode?@Lombo – Dolphin Mar 29 '22 at 02:35