Java equals() and hashCode() Contract

java-hashcode

The Java super class java.lang.Object defines two important methods:

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

In this post, I will first show an example of a common mistake, and then explain how the equals() and hashCode() contract works.

1. A common mistake

The common mistake is shown in the example below.

import java.util.HashMap;
 
public class Apple {
	private String color;
 
	public Apple(String color) {
		this.color = color;
	}
 
	public boolean equals(Object obj) {
		if(obj==null) return false;
		if (!(obj instanceof Apple))
			return false;	
		if (obj == this)
			return true;
		return this.color.equals(((Apple) obj).color);
	}
 
	public static void main(String[] args) {
		Apple a1 = new Apple("green");
		Apple a2 = new Apple("red");
 
		//hashMap stores apple type and its quantity
		HashMap<Apple, Integer> m = new HashMap<Apple, Integer>();
		m.put(a1, 10);
		m.put(a2, 20);
		System.out.println(m.get(new Apple("green")));
	}
}

In the main method, two apples ("green" and "red") are created and put to a HashMap. However, when the map is asked to provide the green apple, the green apple is not found. The program above prints null. We are sure that the green apple is stored in the hashMap when inspecting the HashMap in the debugger.

What causes the issue?

2. Problem caused by hashCode()

The problem is caused by the un-overridden method "hashCode()". The contract between equals() and hashCode() is:
1) If two objects are equal, then they must have the same hash code.
2) If two objects have the same hash code, they may or may not be equal.

The idea behind a Map is to be able to find an object faster than a linear search. Using hashed keys to locate objects is a two-step process. Internally, the HashMap is implemented as an array of Entry objects. Each Entry has a pair and a pointer pointing to the next Entry. The hash code of the key object is the index for addressing the array. This locates the linked list of Entries in that cell of the array. The linked list in the cell is then searched linearly by using equals() to determine if two objects are equal.

The default implementation of hashCode() in Object class returns distinct integers for different objects. Therefore, the second apple has a different hash code.

The HashMap is organized like a sequence of buckets. The key objects are put into different buckets. It takes time of O(1) to get to the right bucket because it is an array access with the index. Therefore, it's a good practice to evenly distribute the objects into those buckets, i.e., having a hashCode() method that produces evenly distributed hash code. (Not the main point here though)

The solution is to add the hashCode method to the Apple class. Here I just use the color string's length for demonstration.

public int hashCode(){
	return this.color.hashCode();	
}
Category >> Common Methods >> Diagram  
If you want someone to read your code, please put the code inside <pre><code> and </code></pre> tags. For example:
<pre><code> 
String foo = "bar";
</code></pre>

  1. Chakradhar on 2013-9-26

    If you execute the code without the hasCode implementation, it won’t even call the equals method. It will check the equals only when you are comparing the objects (using comparator or comparable…) or in the case, when the hashCode is implemented.

  2. prem kumar on 2013-10-16

    Good explanation. I think the readers should read http://javahash.com/java-hashcode-and-equals-most-important-things-to-consider/ too to get a complete picture as both the articles are complimentary

  3. aly on 2013-12-9

    Nice one. Thanks for sharing. I will also http://muhammadkhojaye.blogspot.co.uk/2010/02/java-hashing.html for more examples and scenarios. Cheers,

  4. Franco on 2014-1-20

    Hi, I’m learning Java and I’m trying to figure out the comparison of the equals method:
    return this.color == ((Apple) obj).color;

    you are comparing two strings with the == operator; don’t you have to use the equals method of the strings? Thank you

  5. ryanlr on 2014-1-25

    Right. It is corrected. Thanks!

  6. Franco on 2014-1-28

    You’re welcome. Thanks for the many interesting articles published; I found them very instructive!

  7. Ashish Thakran on 2014-7-23

    HashMap works on the principle of hashing. In order to understand the working of HashMap one has to understand hashing.

    Below link can be useful to find out the working of HashMap

    How HashMap works in Java

  8. Morten Christensen on 2014-11-12

    I find it tedious to implement equals() and hashCode() by hand. I also see too many mistakes in code in this area. Better to automate this, so I have just released a free open source tool VALJOGen (valjogen.41concepts.com) which can generate your value classes with setters/getters (*), Object.hashCode, Object.equals, Object.toString, Comparable.compareTo and more from plain java interfaces. The generated output can be automatically updated when you change your interfaces – no need to maintain the generated code. Let me know what you think?

  9. Hassan Rajabi on 2014-12-21

    Hi every one …

    Excuse me ,I am of a question , but I don’t know what is it it’s subject to ask..

    I wanna know that when the System.currentTimeMillis() in java will became zero , I mean when it will start again ?

  10. ASaraswat on 2015-1-30

    I think it would be helpfull to add that if you use same object reference as it was stored in map i.e. System.out.println(m.get(a1)); you will see the correct result. This explains that if hashCode is not overridden, a default implementation will be used which is always identical for same object. Having sailed that, you should always override hashCode method if object is going to be used in hash based collection

  11. Partha Pratim Sanyal on 2016-4-24

    HashMap is not an array of arrays, Its just one array of Entry objects, and Entry consists of a Key, Value pair.

  12. Edgar Boswell Simpson III on 2017-2-10

    “The default implementation of hashCode() in Object class returns distinct integers for different objects”

    no, it doesn’t.

    Here is the javadoc for Object.hashCode()

    As much as is reasonably practical, the hashCode method defined by
    * class {@code 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.)

    Here’s the thing; objects get moved around during GC, so two different objects can have the same address — at different points in time. the hash value for a given object is “set” the first time you call the “hashCode()” method. so put it all together and the above statement is categorically false. I have personally seen multiple objects have the same hash value.

  13. Hussein on 2017-9-22

    If 2 objects are equal, they MUST have the same hash code.

    If 2 objects have the same hash code, it doesn’t mean that they are equal.

    Overriding equals() alone will make your business fail with hashing data structures like: HashSet, HashMap, HashTable … etc.

    Overriding hashcode() alone doesn’t force java to ignore memory addresses when comparing 2 objects.

    Check this tutorial: http://programmergate.com/working-hashcode-equals-java/

Leave a comment

*