...
Failure to follow this contract is a common source of bugs. Notably, immutable objects are exempt because they need not override the hashcode()
method.
Noncompliant Code Example
Even when the equals()
method conveys logical equivalence between classes, the hashCode()
method returns distinct numbers as opposed to returning the same values, as expected by the contract. This noncompliant code example stores a credit card number into a HashMap
and retrieves it. The expected retrieved value is Java
, however, null
is returned instead. The reason for this erroneous behavior is that the hashCode
method is not overridden which means that a different bucket would be looked into than was used to store the original value.
Code Block | ||
---|---|---|
| ||
import java.util.Map; import java.util.HashMap; public final class CreditCard { private final int number; public CreditCard(int number) { this.number = (short) number; } public boolean equals(Object o) { if (o == this) { return true; } if (!(o instanceof CreditCard)) { return false; } CreditCard cc = (CreditCard)o; return cc.number == number; } public static void main(String[] args) { Map m = new HashMap(); m.put(new CreditCard(100), "Java"); // Assuming Integer.MAX_VALUE is the largest number for card System.out.println(m.get(new CreditCard(100))); } } |
Compliant Solution
Wiki Markup |
---|
This compliant solution shows how the {{hashCode()}} method can be overridden so that the same value is generated for any two instances that compare equal when {{Object.equals()}} is used. Bloch discusses the recipe to generate such a hash function in good detail \[[Bloch 08|AA. Java References#Bloch 08]\]. |
Code Block | ||
---|---|---|
| ||
import java.util.Map; import java.util.HashMap; public final class CreditCard { private final int number; public CreditCard(int number) { this.number = (short) number; } public boolean equals(Object o) { if (o == this) { return true; } if (!(o instanceof CreditCard)) { return false; } CreditCard cc = (CreditCard)o; return cc.number == number; } public int hashCode() { int result = 7; result = 37*result + number; return result; } public static void main(String[] args) { Map m = new HashMap(); m.put(new CreditCard(100), "Java"); System.out.println(m.get(new CreditCard(100))); } } |
Risk Assessment
Overriding the method equals()
method without correspondlingly correspondingly overriding the method hashCode()
method can lead to unexpected results.
...