617

What issues / pitfalls must be considered when overriding equals and hashCode?

George Stocker
  • 55,025
  • 29
  • 167
  • 231
Matt Sheppard
  • 111,039
  • 46
  • 105
  • 128

11 Answers11

1460

The theory (for the language lawyers and the mathematically inclined):

equals() (javadoc) must define an equivalence relation (it must be reflexive, symmetric, and transitive). In addition, it must be consistent (if the objects are not modified, then it must keep returning the same value). Furthermore, o.equals(null) must always return false.

hashCode() (javadoc) must also be consistent (if the object is not modified in terms of equals(), it must keep returning the same value).

The relation between the two methods is:

Whenever a.equals(b), then a.hashCode() must be same as b.hashCode().

In practice:

If you override one, then you should override the other.

Use the same set of fields that you use to compute equals() to compute hashCode().

Use the excellent helper classes EqualsBuilder and HashCodeBuilder from the Apache Commons Lang library. An example:

public class Person {
    private String name;
    private int age;
    // ...

    @Override
    public int hashCode() {
        return new HashCodeBuilder(17, 31). // two randomly chosen prime numbers
            // if deriving: appendSuper(super.hashCode()).
            append(name).
            append(age).
            toHashCode();
    }

    @Override
    public boolean equals(Object obj) {
       if (!(obj instanceof Person))
            return false;
        if (obj == this)
            return true;

        Person rhs = (Person) obj;
        return new EqualsBuilder().
            // if deriving: appendSuper(super.equals(obj)).
            append(name, rhs.name).
            append(age, rhs.age).
            isEquals();
    }
}

Also remember:

When using a hash-based Collection or Map such as HashSet, LinkedHashSet, HashMap, Hashtable, or WeakHashMap, make sure that the hashCode() of the key objects that you put into the collection never changes while the object is in the collection. The bulletproof way to ensure this is to make your keys immutable, which has also other benefits.

Mr Bingley
  • 324
  • 1
  • 10
Antti Kissaniemi
  • 17,999
  • 13
  • 51
  • 47
  • 12
    Additional point about appendSuper(): you should use it in hashCode() and equals() if and only if you want to inherit the equality behavior of the superclass. For instance, if you derive straight from Object, there's no point because all Objects are distinct by default. – Antti Kissaniemi May 28 '09 at 19:03
  • 1
    Special care must be taken of the transient fields. – aviad Apr 12 '11 at 12:36
  • 4
    A great discussion about this question in Effective Java book – K'' Aug 12 '11 at 18:48
  • 315
    You can get Eclipse to generate the two methods for you: Source > Generate hashCode() and equals(). – Rok Strniša Nov 22 '11 at 18:58
  • 1
    does it matter if we all randomly chose the same prime numbers? – zod Jul 12 '12 at 09:10
  • 28
    Same is true with Netbeans: http://developmentality.wordpress.com/2010/08/24/java-creating-correct-equals-and-hashcode-method/ – seinecle Aug 11 '12 at 07:59
  • 2
    @Darthenius: yours is the most useful! – QED Aug 14 '12 at 23:23
  • *make sure that the hashCode() of the key objects that you put into the collection never changes while the object is in the collection* This is exactly why overriding equals and hashcode together may not be necessary. Having hashCode pretty much precludes any changes to the object state while equals can tolerate fully mutable objects. You can safely put a mutable object into list as long as the equals contract remains intact but it's untrue for hashset/hashtables. Also if you wish a class to be able to server as key in hash structure it has to be designed as such (not just having hashCode) – bestsss Feb 10 '13 at 14:34
  • @bestsss: A general rule which is good to follow is that at any given time when a mutable aspect of an object's state might change, the object should have one well-defined owner. If an object overrides `equals` so as to depend upon some mutable state, any Dictionary in which it was stored would "own" that aspect of its state. Since any execution context which tried to alter that state would have to own it, that would imply that the object must be removed from the Dictionary first. Otherwise, if one wants to bend this rule, override `hashCode` to depend only upon immutable properties. – supercat Aug 04 '13 at 16:48
  • 1
    @Darthenius or the shortcut: `ALT` `Shift` `S` and then `h`. – mike Aug 29 '13 at 08:55
  • 6
    @Darthenius Eclipse generated equals uses getClass() which might cause problems in some cases (see Effective Java item 8) – AndroidGecko Dec 08 '13 at 18:46
  • 7
    The first null check is not necessary given the fact that `instanceof` returns false if its first operand is null (Effective Java again). – izaban Dec 13 '13 at 19:51
  • 1
    @AndroidGecko maybe it did in the past. Eclipse Kepler did not generate code containing getClass(). – Rui Marques Jan 24 '14 at 13:09
  • 3
    Android Studio can also generate equals() and hashCode() for you. – Brian Feb 10 '14 at 20:01
  • 1
    The mathematical term is "equivalence relation", not "equality relation". – Mike Housky Mar 18 '14 at 04:52
  • equals is used to add/remove elements from collections like CopyOnWriteArraySet, HashSet if hashCode is equal for two different objects, etc. equals need to be symmetric i.e. if B.equals(C) returns true then C.equals(B) should return the same result. Otherwise your add/remove on those XXXSets behave in a confusing manner. http://stackoverflow.com/questions/24920563/overriding-equals-for-copyonwritearrayset-add-and-remove – yalkris Jul 28 '14 at 21:06
  • You are re-calculating hashcode every time hashCode() is called. If the object is immutable, cache the calculated hashcode in the instance. Refer the hashCode impl in String class. – Amit Parashar May 28 '15 at 09:34
  • 3
    when using "instanceof" instead of "getClass()" symmetry would not always be maintained – AbrahamDaniel Jun 03 '15 at 03:31
  • 1
    This answer is only half of the story. It fails to mention any of the pitfalls when overriding the equals method in a subclass. It is actually misleading in that simply adding appendSuper in a derived class will solve the problem. It will almost certainly break either symmetry or transitivity. – steinybot Jun 29 '15 at 02:37
  • Unfortunately no answer really solves the problem except perhaps http://stackoverflow.com/a/55736/367796. Even then I would be more inclined to go with @Blaisorblade comment to use the canEqual approach http://stackoverflow.com/questions/27581/what-issues-should-be-considered-when-overriding-equals-and-hashcode-in-java#comment10518068_55736 – steinybot Jun 29 '15 at 02:37
  • @AnttiSykäri you can also add some example like- when we want to insert user defined object into SET that time we need to implement hashCode and equals method so it will add only unique object into SET – Manish Nagar Feb 02 '16 at 06:30
  • IntelliJ has a wizard too: right-click the class name > Generate.. (or ⌘N) > equals() and hashCode(). – philo Feb 23 '16 at 04:11
  • 3
    why `instanceof` instead `if((obj == null) || (obj.getClass() != this.getClass()))` ? instanceof could create problem for parent and child. – Asif Mushtaq Mar 25 '16 at 18:25
  • surprised by the fact that `enum` is not a part of the answer, shall we not be concerned over such fields? – Naman Oct 13 '16 at 10:49
  • "Use the same set of fields that you use to compute equals() to compute hashCode()" I was taught that hashcode was the "quick look-up", just to narrow the scope of what then needs a full "equals" check. So, in most situations, I would just pick one field (e.g. "age" in this example) rather than always including all the fields. Is that bad practice? – David Lavender Dec 05 '17 at 16:32
297

There are some issues worth noticing if you're dealing with classes that are persisted using an Object-Relationship Mapper (ORM) like Hibernate, if you didn't think this was unreasonably complicated already!

Lazy loaded objects are subclasses

If your objects are persisted using an ORM, in many cases you will be dealing with dynamic proxies to avoid loading object too early from the data store. These proxies are implemented as subclasses of your own class. This means thatthis.getClass() == o.getClass() will return false. For example:

Person saved = new Person("John Doe");
Long key = dao.save(saved);
dao.flush();
Person retrieved = dao.retrieve(key);
saved.getClass().equals(retrieved.getClass()); // Will return false if Person is loaded lazy

If you're dealing with an ORM, using o instanceof Person is the only thing that will behave correctly.

Lazy loaded objects have null-fields

ORMs usually use the getters to force loading of lazy loaded objects. This means that person.name will be null if person is lazy loaded, even if person.getName() forces loading and returns "John Doe". In my experience, this crops up more often in hashCode() and equals().

If you're dealing with an ORM, make sure to always use getters, and never field references in hashCode() and equals().

Saving an object will change its state

Persistent objects often use a id field to hold the key of the object. This field will be automatically updated when an object is first saved. Don't use an id field in hashCode(). But you can use it in equals().

A pattern I often use is

if (this.getId() == null) {
    return this == other;
}
else {
    return this.getId().equals(other.getId());
}

But: you cannot include getId() in hashCode(). If you do, when an object is persisted, its hashCode changes. If the object is in a HashSet, you'll "never" find it again.

In my Person example, I probably would use getName() for hashCode and getId() plus getName() (just for paranoia) for equals(). It's okay if there are some risk of "collisions" for hashCode(), but never okay for equals().

hashCode() should use the non-changing subset of properties from equals()

maaartinus
  • 40,991
  • 25
  • 130
  • 292
Johannes Brodwall
  • 6,977
  • 5
  • 29
  • 27
  • 2
    @Johannes Brodwall: i don't understand `Saving an object will change it's state`! `hashCode` must return `int`, so how will you use `getName()`? Can you give an example for your `hashCode` – jimmybondy Nov 01 '12 at 14:14
  • @jimmybondy: getName will return a String object which also has a hashCode which can be used – mateusz.fiolka Mar 02 '13 at 13:15
85

A clarification about the obj.getClass() != getClass().

This statement is the result of equals() being inheritance unfriendly. The JLS (Java language specification) specifies that if A.equals(B) == true then B.equals(A) must also return true. If you omit that statement inheriting classes that override equals() (and change its behavior) will break this specification.

Consider the following example of what happens when the statement is omitted:

    class A {
      int field1;

      A(int field1) {
        this.field1 = field1;
      }

      public boolean equals(Object other) {
        return (other != null && other instanceof A && ((A) other).field1 == field1);
      }
    }

    class B extends A {
        int field2;

        B(int field1, int field2) {
            super(field1);
            this.field2 = field2;
        }

        public boolean equals(Object other) {
            return (other != null && other instanceof B && ((B)other).field2 == field2 && super.equals(other));
        }
    }    

Doing new A(1).equals(new A(1)) Also, new B(1,1).equals(new B(1,1)) result give out true, as it should.

This looks all very good, but look what happens if we try to use both classes:

A a = new A(1);
B b = new B(1,1);
a.equals(b) == true;
b.equals(a) == false;

Obviously, this is wrong.

If you want to ensure the symmetric condition. a=b if b=a and the Liskov substitution principle call super.equals(other) not only in the case of B instance, but check after for A instance:

if (other instanceof B )
   return (other != null && ((B)other).field2 == field2 && super.equals(other)); 
if (other instanceof A) return super.equals(other); 
   else return false;

Which will output:

a.equals(b) == true;
b.equals(a) == true;

Where, if a is not a reference of B, then it might be a be a reference of class A (because you extend it), in this case you call super.equals() too.

BartoszKP
  • 32,105
  • 13
  • 92
  • 123
Ran Biron
  • 6,091
  • 4
  • 33
  • 66
  • 2
    You can make equals symmetric this way (if comparing a superclass object with subclass object, always use the equals of the subclass) if (obj.getClass() != this.getClass() && obj.getClass().isInstance(this)) return obj.equals(this); – pihentagy Feb 25 '10 at 10:40
  • 5
    @pihentagy - then I'd get a stackoverflow when the implementation class doesn't override the equals method. not fun. – Ran Biron Dec 06 '10 at 19:16
  • 2
    You won't get a stackoverflow. If the equals method is not overridden, you will call the same code again, but the condition for recursion will always be false! – Jacob Raihle Aug 04 '13 at 12:32
  • @pihentagy: How does that behave if there are two different derived classes? If a `ThingWithOptionSetA` can be equal to a `Thing` provided that all the extra options have default values, and likewise for a `ThingWithOptionSetB`, then it should be possible for a `ThingWithOptionSetA` to be compare equal to a `ThingWithOptionSetB` only if all non-base properties of both objects match their defaults, but I don't see how you test for that. – supercat Dec 28 '13 at 19:41
  • 8
    The problem with this it that it breaks transitivity. If you add `B b2 = new B(1,99)`, then `b.equals(a) == true` and `a.equals(b2) == true` but `b.equals(b2) == false`. – nickgrim Jun 25 '15 at 10:24
46

For an inheritance-friendly implementation, check out Tal Cohen's solution, How Do I Correctly Implement the equals() Method?

Summary:

In his book Effective Java Programming Language Guide (Addison-Wesley, 2001), Joshua Bloch claims that "There is simply no way to extend an instantiable class and add an aspect while preserving the equals contract." Tal disagrees.

His solution is to implement equals() by calling another nonsymmetric blindlyEquals() both ways. blindlyEquals() is overridden by subclasses, equals() is inherited, and never overridden.

Example:

class Point {
    private int x;
    private int y;
    protected boolean blindlyEquals(Object o) {
        if (!(o instanceof Point))
            return false;
        Point p = (Point)o;
        return (p.x == this.x && p.y == this.y);
    }
    public boolean equals(Object o) {
        return (this.blindlyEquals(o) && o.blindlyEquals(this));
    }
}

class ColorPoint extends Point {
    private Color c;
    protected boolean blindlyEquals(Object o) {
        if (!(o instanceof ColorPoint))
            return false;
        ColorPoint cp = (ColorPoint)o;
        return (super.blindlyEquals(cp) && 
        cp.color == this.color);
    }
}

Note that equals() must work across inheritance hierarchies if the Liskov Substitution Principle is to be satisfied.

reevesy
  • 3,354
  • 1
  • 24
  • 22
Kevin Wong
  • 13,690
  • 11
  • 40
  • 49
  • 10
    Have a look at the canEqual method explained here - the same principle makes both solutions work, but with canEqual you don't compare the same fields twice (above, p.x == this.x will be tested in both directions): http://www.artima.com/lejava/articles/equality.html – Blaisorblade Dec 14 '11 at 01:43
  • 2
    In any case, I don't think this is a good idea. It makes the Equals contract unnecessarily confusing - someone who takes two Point parameters, a and b, has to be conscious of the possibility that a.getX() == b.getX() and a.getY() == b.getY() can be true, but a.equals(b) and b.equals(a) both be false (if only one is a ColorPoint). – Kevin Aug 12 '14 at 01:05
  • Basically, this is like `if (this.getClass() != o.getClass()) return false`, but flexible in that it only returns false if the derived class(es) bother to modify equals. Is that right? – Aleksandr Dubinsky Feb 19 '16 at 16:37
31

Still amazed that none recommended the guava library for this.

 //Sample taken from a current working project of mine just to illustrate the idea

    @Override
    public int hashCode(){
        return Objects.hashCode(this.getDate(), this.datePattern);
    }

    @Override
    public boolean equals(Object obj){
        if ( ! obj instanceof DateAndPattern ) {
            return false;
        }
        return Objects.equal(((DateAndPattern)obj).getDate(), this.getDate())
                && Objects.equal(((DateAndPattern)obj).getDate(), this.getDatePattern());
    }
Andy Thomas
  • 78,842
  • 10
  • 93
  • 142
Eugene
  • 102,901
  • 10
  • 149
  • 252
  • 24
    java.util.Objects.hash() and java.util.Objects.equals() are part of Java 7 (released in 2011) so you don't need Guava for this. – herman Jul 23 '13 at 13:33
  • 1
    of course, but you should avoid that since Oracle is not providing public updates anymore for Java 6 (this has been the case since February 2013). – herman Jul 25 '13 at 09:48
  • 6
    Your `this` in `this.getDate()` means nothing (other than clutter) – Steve Kuo Apr 29 '14 at 04:49
  • 1
    Your "not instanceof" expression needs an extra bracket: `if (!(otherObject instanceof DateAndPattern)) {`. Agree with hernan and Steve Kuo (though that one's a matter of personal preference), but +1 nonetheless. – Amos M. Carpenter Dec 11 '15 at 03:27
28

There are two methods in super class as java.lang.Object. We need to override them to custom object.

public boolean equals(Object obj)
public int hashCode()

Equal objects must produce the same hash code as long as they are equal, however unequal objects need not produce distinct hash codes.

public class Test
{
    private int num;
    private String data;
    public boolean equals(Object obj)
    {
        if(this == obj)
            return true;
        if((obj == null) || (obj.getClass() != this.getClass()))
            return false;
        // object must be Test at this point
        Test test = (Test)obj;
        return num == test.num &&
        (data == test.data || (data != null && data.equals(test.data)));
    }

    public int hashCode()
    {
        int hash = 7;
        hash = 31 * hash + num;
        hash = 31 * hash + (null == data ? 0 : data.hashCode());
        return hash;
    }

    // other methods
}

If you want get more, please check this link as http://www.javaranch.com/journal/2002/10/equalhash.html

This is another example, http://java67.blogspot.com/2013/04/example-of-overriding-equals-hashcode-compareTo-java-method.html

Have Fun! @.@

Luna Kong
  • 2,745
  • 21
  • 18
  • Sorry but I don't understand this statement about hashCode method: it is not legal if it uses more variables than equals(). But if I code with more variables, my code compiles. Why is it not legal? – Sam Nov 14 '18 at 15:19
20

There are a couple of ways to do your check for class equality before checking member equality, and I think both are useful in the right circumstances.

  1. Use the instanceof operator.
  2. Use this.getClass().equals(that.getClass()).

I use #1 in a final equals implementation, or when implementing an interface that prescribes an algorithm for equals (like the java.util collection interfaces—the right way to check with with (obj instanceof Set) or whatever interface you're implementing). It's generally a bad choice when equals can be overridden because that breaks the symmetry property.

Option #2 allows the class to be safely extended without overriding equals or breaking symmetry.

If your class is also Comparable, the equals and compareTo methods should be consistent too. Here's a template for the equals method in a Comparable class:

final class MyClass implements Comparable<MyClass>
{

  …

  @Override
  public boolean equals(Object obj)
  {
    /* If compareTo and equals aren't final, we should check with getClass instead. */
    if (!(obj instanceof MyClass)) 
      return false;
    return compareTo((MyClass) obj) == 0;
  }

}
erickson
  • 249,448
  • 50
  • 371
  • 469
  • 1
    +1 for this. Neither getClass() nor instanceof is a panacea, and this is a good explanation of how to approach both. Don't think there's any reason not to do this.getClass() == that.getClass() instead of using equals(). – Paul Cantrell Apr 24 '13 at 21:48
  • There is one problem with this. Anonymous classes which do not add any aspects nor override the equals method will fail the getClass check even though they should be equal. – steinybot Jun 29 '15 at 02:27
  • @Steiny It's not clear to me that objects of different types should be equal; I'm thinking of different implementations of an interface as a common anonymous class. Can you give an example to support your premise? – erickson Jun 29 '15 at 23:45
  • MyClass a = new MyClass(123); MyClass b = new MyClass(123) { // Override some method }; // a.equals(b) is false when using this.getClass().equals(that.getClass()) – steinybot Jul 07 '15 at 02:53
  • 1
    @Steiny Right. As it should in most cases, especially if a method is overridden instead of added. Consider my example above. If it weren't `final`, and the `compareTo()` method were overridden to reverse the sort order, instances of the subclass and superclass should not be considered equal. When these objects were used together in a tree, keys that were "equal" according to an `instanceof` implementation might not be findable. – erickson Jul 07 '15 at 15:41
16

For equals, look into Secrets of Equals by Angelika Langer. I love it very much. She's also a great FAQ about Generics in Java. View her other articles here (scroll down to "Core Java"), where she also goes on with Part-2 and "mixed type comparison". Have fun reading them!

Johannes Schaub - litb
  • 466,055
  • 116
  • 851
  • 1,175
11

equals() method is used to determine the equality of two objects.

as int value of 10 is always equal to 10. But this equals() method is about equality of two objects. When we say object, it will have properties. To decide about equality those properties are considered. It is not necessary that all properties must be taken into account to determine the equality and with respect to the class definition and context it can be decided. Then the equals() method can be overridden.

we should always override hashCode() method whenever we override equals() method. If not, what will happen? If we use hashtables in our application, it will not behave as expected. As the hashCode is used in determining the equality of values stored, it will not return the right corresponding value for a key.

Default implementation given is hashCode() method in Object class uses the internal address of the object and converts it into integer and returns it.

public class Tiger {
  private String color;
  private String stripePattern;
  private int height;

  @Override
  public boolean equals(Object object) {
    boolean result = false;
    if (object == null || object.getClass() != getClass()) {
      result = false;
    } else {
      Tiger tiger = (Tiger) object;
      if (this.color == tiger.getColor()
          && this.stripePattern == tiger.getStripePattern()) {
        result = true;
      }
    }
    return result;
  }

  // just omitted null checks
  @Override
  public int hashCode() {
    int hash = 3;
    hash = 7 * hash + this.color.hashCode();
    hash = 7 * hash + this.stripePattern.hashCode();
    return hash;
  }

  public static void main(String args[]) {
    Tiger bengalTiger1 = new Tiger("Yellow", "Dense", 3);
    Tiger bengalTiger2 = new Tiger("Yellow", "Dense", 2);
    Tiger siberianTiger = new Tiger("White", "Sparse", 4);
    System.out.println("bengalTiger1 and bengalTiger2: "
        + bengalTiger1.equals(bengalTiger2));
    System.out.println("bengalTiger1 and siberianTiger: "
        + bengalTiger1.equals(siberianTiger));

    System.out.println("bengalTiger1 hashCode: " + bengalTiger1.hashCode());
    System.out.println("bengalTiger2 hashCode: " + bengalTiger2.hashCode());
    System.out.println("siberianTiger hashCode: "
        + siberianTiger.hashCode());
  }

  public String getColor() {
    return color;
  }

  public String getStripePattern() {
    return stripePattern;
  }

  public Tiger(String color, String stripePattern, int height) {
    this.color = color;
    this.stripePattern = stripePattern;
    this.height = height;

  }
}

Example Code Output:

bengalTiger1 and bengalTiger2: true 
bengalTiger1 and siberianTiger: false 
bengalTiger1 hashCode: 1398212510 
bengalTiger2 hashCode: 1398212510 
siberianTiger hashCode: –1227465966
user1431282
  • 5,654
  • 12
  • 44
  • 64
rohan kamat
  • 565
  • 5
  • 12
7

Logically we have:

a.getClass().equals(b.getClass()) && a.equals(b)a.hashCode() == b.hashCode()

But not vice-versa!

Hermes
  • 486
  • 5
  • 10
Khaled.K
  • 5,516
  • 1
  • 30
  • 47
6

One gotcha I have found is where two objects contain references to each other (one example being a parent/child relationship with a convenience method on the parent to get all children).
These sorts of things are fairly common when doing Hibernate mappings for example.

If you include both ends of the relationship in your hashCode or equals tests it's possible to get into a recursive loop which ends in a StackOverflowException.
The simplest solution is to not include the getChildren collection in the methods.

Darren Greaves
  • 3,236
  • 4
  • 26
  • 32
  • 5
    I think the underlying theory here is to distinguish between the _attributes_, _aggregates_ and _associatinos_ of an object. The _asssociations_ should not participate in `equals()`. If a mad scientist created a duplicate of me we would be equivalent. But we would not have the same father. – Raedwald Sep 29 '11 at 09:28