Ответ
Потому что контракт метода Object.equals() подразумевает, что объекты должны быть сравнимы только внутри своей иерархии наследования. Основные причины:
- Разная семантика (поведение): Классы определяют не только данные (поля), но и поведение (методы). Объекты с одинаковыми данными, но разным поведением, по смыслу не эквивалентны.
- Стандартная реализация
equals(): По умолчанию (в классеObject) и в большинстве корректных реализаций используется проверка на точное совпадение типов (например,this.getClass() != obj.getClass()).
Пример:
class Point {
private int x, y;
// конструктор, геттеры
@Override
public boolean equals(Object o) {
if (this == o) return true;
// Проверка на точное совпадение класса
if (o == null || getClass() != o.getClass()) return false;
Point point = (Point) o;
return x == point.x && y == point.y;
}
}
class ColoredPoint extends Point {
private Color color;
// конструктор, геттеры
@Override
public boolean equals(Object o) {
// Также требует точного совпадения класса ColoredPoint
if (!super.equals(o)) return false;
if (o == null || getClass() != o.getClass()) return false;
ColoredPoint that = (ColoredPoint) o;
return Objects.equals(color, that.color);
}
}
Point p = new Point(1, 2);
ColoredPoint cp = new ColoredPoint(1, 2, Color.RED);
System.out.println(p.equals(cp)); // false - разные классы
Нарушение этого правила (сравнение объектов разных классов) ведёт к нарушению ключевых свойств equals(): симметричности (a.equals(b) == b.equals(a)) и транзитивности.