The full picture
class Point { int x, y; /* equals compares x,y */ }
class ColorPoint extends Point { Color c; /* equals also compares c */ }
Point p = new Point(1, 2);
ColorPoint cp = new ColorPoint(1, 2, RED);
p.equals(cp); // true (Point ignores color)
cp.equals(p); // false (ColorPoint checks color) -> SYMMETRY BROKEN
// There is NO way to extend an instantiable class with a new value
// component while preserving the contract (Effective Java, Item 10).
// Answer: prefer composition — or model values as records (final).- Use
getClass()equality or make the classfinal/a record;instanceof-based equals is only safe when subclasses add no state. - Always base
hashCodeon exactly the fields used inequals—Objects.hash(...)or record generation. - For entities with DB identity, equality by business key or id (careful: id is null before persist) — never by mutable state.