Why Java’s equals and hashCode Must Work Together – A Complete Guide
This article explains the purpose and contract of Java's equals and hashCode methods, shows how the default implementations work, demonstrates why String overrides equals, outlines the three-step equality check, and provides guidelines for correctly overriding these methods in custom classes.
Purpose of equals
The equals method compares two objects for logical equality. In Object, the default implementation simply checks whether the two references point to the same memory address using ==. Therefore it returns true only when the two references are identical.
public boolean equals(Object obj) {
return this == obj;
}When two distinct String objects are compared, the result is true because String overrides equals to compare the actual character content.
public static void main(String[] args) {
String str1 = new String("mikechen");
String str2 = new String("mikechen");
System.out.println(str1.equals(str2)); // prints true
}Implementation of String.equals
The overridden method follows three steps:
Check if the two references are identical ( this == anObject).
If not identical, verify that anObject is an instance of String.
Finally, compare the character arrays of both strings element by element.
public boolean equals(Object anObject) {
if (this == anObject) return true;
if (anObject instanceof String) {
String anotherString = (String) anObject;
int n = value.length;
if (n == anotherString.value.length) {
char[] v1 = value;
char[] v2 = anotherString.value;
for (int i = 0; i < n; i++) {
if (v1[i] != v2[i]) return false;
}
return true;
}
}
return false;
}All built‑in Java classes (e.g., Integer, Double) implement equals in a similar fashion.
Contract for Overriding equals
Reflexive : x.equals(x) must return true for any non‑null x.
Symmetric : If x.equals(y) returns true, then y.equals(x) must also return true.
Transitive : If x.equals(y) and y.equals(z) both return true, then x.equals(z) must return true.
Consistent : Repeated calls to x.equals(y) must consistently return the same result as long as neither object is modified.
Non‑null : x.equals(null) must return false.
Purpose of hashCode
The hashCode method returns an integer hash value used by hash‑based collections (e.g., HashMap, HashSet) to locate the bucket where an object may be stored. public native int hashCode(); Two main roles:
1. Fast lookup
The hash code maps an object to a bucket, allowing the collection to quickly narrow down where the object might be.
2. Object matching
After locating the bucket, the collection uses equals to compare the target object with existing entries, ensuring correct identification.
If a bucket already contains objects, equals determines whether the new object is a duplicate; if not, it is added to the bucket’s linked list.
Relationship Between equals and hashCode
Consistency : If a.equals(b) is true, then a.hashCode() must equal b.hashCode(). The reverse is not required because different objects can share the same hash code (collision).
Necessity : Overriding only equals without also overriding hashCode can break hash‑based collections, causing objects to be unreachable.
Recommendation : Always override hashCode whenever you override equals to maintain the contract required by the Java Collections Framework.
Mike Chen's Internet Architecture
Over ten years of BAT architecture experience, shared generously!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
