27. Key Object Methods to Override
Object provides toString(), equals(), hashCode(), clone(), and finalize() โ only toString(), equals(), and hashCode() should routinely be overridden; prefer records for data classes.
Explanation
toString(): called by System.out.println, string concatenation, and logging. Default is ClassName@hexHashCode โ almost never useful. Always override in domain classes or use records.
equals() and hashCode(): covered together in entry #9. Must be overridden together; records do this automatically.
clone(): the Cloneable interface is a poorly-designed marker; Object.clone() does a shallow copy and requires catching CloneNotSupportedException. The preferred alternative is a copy constructor (new Foo(other)) or a static factory. Avoid implementing clone() in new code.
finalize(): called by the GC before an object is reclaimed. Deprecated since Java 9 and removed from consideration in modern Java. It is non-deterministic, slow, and error-prone. Use try-with-resources or Cleaner (Java 9+) instead.
Example
import java.util.Objects;
public class ObjectMethods {
static class Point {
final int x, y;
Point(int x, int y) { this.x = x; this.y = y; }
// Copy constructor โ preferred over clone()
Point(Point other) { this(other.x, other.y); }
@Override
public String toString() {
return "Point(" + x + ", " + y + ")";
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Point p)) return false;
return x == p.x && y == p.y;
}
@Override
public int hashCode() {
return Objects.hash(x, y);
}
}
// Records do everything automatically (Java 16+)
record RecordPoint(int x, int y) {}
public static void main(String[] args) {
Point p1 = new Point(1, 2);
Point p2 = new Point(1, 2);
Point p3 = new Point(3, 4);
System.out.println(p1); // Point(1, 2)
System.out.println(p1.equals(p2)); // true
System.out.println(p1.equals(p3)); // false
System.out.println(p1.hashCode() == p2.hashCode()); // true
// Copy constructor
Point copy = new Point(p1);
copy = new Point(copy.x + 1, copy.y); // p1 unchanged
System.out.println(p1 + " vs " + copy);
// Record: toString, equals, hashCode all correct
RecordPoint r1 = new RecordPoint(1, 2);
RecordPoint r2 = new RecordPoint(1, 2);
System.out.println(r1); // RecordPoint[x=1, y=2]
System.out.println(r1.equals(r2)); // true
}
}Sources
- https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/Object.html โ Object class API
- https://www.pearson.com/en-us/subject-catalog/p/effective-java/P200000000138 โ Effective Java, Items 10-13