Object ·
‹ Предыдущий Следующий ›
⏱ 5 минут чтения Обновлено: 2026-09-28

Object. Практические Задания

Класс Object — корень иерархии классов Java: его методы equals(), hashCode() и toString() есть у любого объекта. По умолчанию equals() сравнивает ссылки, hashCode() не зависит от полей, а toString() возвращает строку вида Book@1b6d3586. Поэтому для классов-значений (точка, книга, деньги) эти три метода почти всегда переопределяют вместе.

На странице 3 практические задачи.

Что повторить перед решением

Задачи опираются на три урока: класс Object и его методы, метод equals() и его контракт, метод toString(). Краткая шпаргалка:

Метод Что делает реализация Object Когда переопределять
equals(Object o) Сравнивает ссылки, как == Объекты с одинаковыми данными должны считаться равными
hashCode() Возвращает число, не связанное с полями Всегда вместе с equals(): равные объекты обязаны иметь равный хеш-код
toString() getClass().getName() + "@" + Integer.toHexString(hashCode()) Почти всегда: для логов, отладки и вывода в консоль

Задача 1. Методы Object по умолчанию

  1. Создайте класс Book с полями title (String), author (String) и year (int) и конструктором для всех трёх полей. Методы Object не переопределяйте.
  2. Создайте два объекта с одинаковыми данными: new Book("Война и мир", "Толстой", 1869).
  3. Выведите на консоль для каждого объекта: сам объект через System.out.println(book), book.hashCode() и book.getClass().getName().
  4. Выведите результаты сравнений book1 == book2 и book1.equals(book2). Затем создайте ссылку Book book3 = book1; и сравните book1 с book3 обоими способами.
  5. Письменно (в комментарии к коду) объясните каждую строку вывода: из чего состоит строка Book@..., почему equals() вернул false для одинаковых книг и true для book3.

Подсказка: шестнадцатеричное число после @ в выводе println совпадает с Integer.toHexString(book.hashCode()). Проверьте это в коде.

Задача 2. Переопределение toString() и наследование

  1. Переопределите в Book метод toString() так, чтобы он возвращал строку вида Book{title='Война и мир', author='Толстой', year=1869}. Поставьте аннотацию @Override.
  2. Создайте класс EBook extends Book с дополнительным полем fileSizeMb (double). Переопределите toString(), используя super.toString(), чтобы не дублировать поля родителя.
  3. Проверьте три места, где toString() вызывается неявно: System.out.println(book), конкатенация "Книга: " + book и вывод List<Book> через println.
  4. Создайте массив Book[] из трёх книг. Выведите его через System.out.println(array) и через Arrays.toString(array). Объясните, почему результаты отличаются.
  5. Присвойте переменной Book значение null и сравните поведение System.out.println(book) и book.toString(). Затем выведите String.valueOf(book) и Objects.toString(book, "книга не найдена").

Задача 3. equals() и оператор ==: класс Point

  1. Создайте класс Point с полями x и y (int) и переопределите equals(): точки равны, если совпадают обе координаты. Порядок проверок: та же ссылка, null, класс объекта, приведение типа, сравнение полей.
  2. Напишите метод main, который проверяет все пункты контракта equals() и печатает результат каждой проверки:
    а) рефлексивность: p.equals(p);
    б) симметричность: p1.equals(p2) и p2.equals(p1);
    в) транзитивность для трёх равных точек;
    г) сравнение с null возвращает false без исключения;
    д) сравнение с объектом другого класса, например со строкой "1,2", возвращает false.
  3. Добавьте в Point поле String label, которое может быть null, и включите его в сравнение через Objects.equals(label, other.label). Проверьте случаи, когда label равен null у одной и у обеих точек.
  4. Сравните две строки: String a = "java"; и String b = new String("java"); через == и через equals(). Затем сравните два массива int[] с одинаковым содержимым через equals() и через Arrays.equals(). Объясните результаты.

Подсказка: если написать метод с сигнатурой equals(Point other), это будет перегрузка, а не переопределение: HashSet и List.contains() его не вызовут. Аннотация @Override сразу покажет такую ошибку при компиляции.

На чём чаще всего ошибаются

  • Переопределили equals(), но забыли hashCode(). Объекты перестают находиться в HashSet и HashMap, хотя в ArrayList всё работает. Эти два метода переопределяют только парой.
  • Параметр equals(Point other) вместо equals(Object o). Получается перегрузка: коллекции вызывают версию из Object и сравнивают ссылки. Защита — аннотация @Override.
  • Разный набор полей в equals() и hashCode(). Если hashCode() использует поле, которого нет в equals(), у равных объектов окажутся разные хеш-коды. Хешируйте те же поля, что сравниваете (или их подмножество).
  • Сравнение строк и полей-объектов через == внутри equals(). Для ссылочных полей нужен equals(), а если поле может быть null — Objects.equals().
  • Явный вызов obj.toString() там, где obj может быть null. Получите NullPointerException; println(obj), конкатенация и String.valueOf(obj) безопасно выведут null.

Перед отправкой решения сверьтесь с рекомендациями по оформлению кода на Java.

Часто задаваемые вопросы

Нужно ли переопределять equals() и hashCode() в каждом классе?

Нет. Их переопределяют в классах-значениях, которые сравнивают по данным и кладут в HashSet или используют ключами HashMap: точка, деньги, ISBN книги. Сервисам, контроллерам, потокам и другим объектам с «личностью» подходит сравнение по ссылке из Object. А вот toString() полезно переопределять почти везде — для логов.

Можно ли возвращать в hashCode() константу, например 42?

Формально да: контракт не нарушен, равные объекты получат равные хеш-коды. Но все объекты попадут в одну корзину, и HashMap превратится в медленный поиск перебором: поиск будет тем медленнее, чем больше элементов. Используйте Objects.hash() по тем же полям, что и в equals().

Все ли поля стоит выводить в toString()?

Нет. Не выводите пароли, токены и персональные данные: строка из toString() часто попадает в логи. Опасны и двусторонние связи: если Order выводит Customer, а тот — список своих Order, вызовы зациклятся и закончатся StackOverflowError. Для таких полей выводите только идентификатор.

Комментарии

Зарегистрируйтесь или войдите, чтобы иметь возможность оставить комментарий.