Java equals() and hashCode() Contract
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
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(); } |
<pre><code> String foo = "bar"; </code></pre>
-
Trippy_galatic_zebra_man
-
vishal verma
-
bluelurker
-
Sameer Mohanta
-
Manjunath D
-
Rahul Agrawal
-
amit
-
Rahul Agrawal
-
Hussein
-
Edgar Boswell Simpson III
-
Partha Pratim Sanyal
-
ASaraswat
-
Hassan Rajabi
-
Morten Christensen
-
Ashish Thakran
-
Franco
-
ryanlr
-
Franco
-
aly
-
prem kumar
-
Chakradhar