Разберите Java-кейс: "class A { int x; } A a1 = new A(); A a2 = new A(); System.out.println(a1.equals(a2));" — почему результат такой и как правильно реализовать сравнение объектов по содержимому
Коротко: по умолчанию метод `equals` унаследован от `Object` сравнивает ссылки, а не содержимое. Поскольку `a1` и `a2` — разные объекты, a1.equals(a2)a1.equals(a2)a1.equals(a2) вернёт `false`. То же самое эквивалентно сравнению ссылок: a1==a2a1 == a2a1==a2 — тоже `false`. Как правильно сравнивать по содержимому: 1) Переопределить `equals(Object)` так, чтобы сравнивать значимые поля. 2) Переопределить `hashCode()` в соответствии с контрактом `equals` (равные объекты — одинаковые хэш-коды). 3) Соблюдать контракт equals: рефлексивность, симметричность, транзитивность, согласованность и x.equals(null)x.equals(null)x.equals(null) должно возвращать `false`. Пример для вашего класса: ```java import java.util.Objects; class A { int x; A(int x) { this.x = x; } @Override public boolean equals(Object o) { if (this == o) return true; // идентичные ссылки if (o == null || getClass() != o.getClass()) return false; // null/разные классы A other = (A) o; return x == other.x; // сравнение по полю } @Override public int hashCode() { return Integer.hashCode(x); // или Objects.hash(x) } } ``` После этого, если у вас `A a1 = new A(5); A a2 = new A(5);`, то a1.equals(a2)a1.equals(a2)a1.equals(a2) вернёт `true`. Альтернативы: - Для Java 16+ можно использовать `record A(int x);` — равенство и `hashCode` генерируются автоматически. - Для автоматической генерации в старых версиях — Lombok (`@Data`, `@EqualsAndHashCode`).
Как правильно сравнивать по содержимому:
1) Переопределить `equals(Object)` так, чтобы сравнивать значимые поля.
2) Переопределить `hashCode()` в соответствии с контрактом `equals` (равные объекты — одинаковые хэш-коды).
3) Соблюдать контракт equals: рефлексивность, симметричность, транзитивность, согласованность и x.equals(null)x.equals(null)x.equals(null) должно возвращать `false`.
Пример для вашего класса:
```java
import java.util.Objects;
class A {
int x;
A(int x) { this.x = x; }
@Override
public boolean equals(Object o) {
if (this == o) return true; // идентичные ссылки
if (o == null || getClass() != o.getClass()) return false; // null/разные классы
A other = (A) o;
return x == other.x; // сравнение по полю
}
@Override
public int hashCode() {
return Integer.hashCode(x); // или Objects.hash(x)
}
}
```
После этого, если у вас `A a1 = new A(5); A a2 = new A(5);`, то a1.equals(a2)a1.equals(a2)a1.equals(a2) вернёт `true`.
Альтернативы:
- Для Java 16+ можно использовать `record A(int x);` — равенство и `hashCode` генерируются автоматически.
- Для автоматической генерации в старых версиях — Lombok (`@Data`, `@EqualsAndHashCode`).