Object, Equals и HashCode Flashcards
класс Object
Все классы являются наследниками суперкласса Object.
Объект Object может ссылаться на объект любого другого класса.
методы класса Object
- Class getClass() — возвращает в рантайме класс данного объекта.
- int hashCode() — возвращает хеш-код
- boolean equals(Object obj) — сравнивает объекты.
- Object clone() - клонирование объекта
- String toString() — возвращает строковое представление объекта.
- void notify() — просыпается один поток, который ждет на “мониторе” данного объекта.
- void notifyAll() — просыпаются все потоки, которые ждут на “мониторе” данного объекта.
- void wait(long timeout) - поток переходит в режим ожидания в течение указанного времени.
- void wait() - приводит данный поток в ожидание, пока другой поток не вызовет notify() или notifyAll() методы для этого объекта.
- void wait(long timeout, int nanos) - приводит данный поток в ожидание, пока другой поток не вызовет notify() или notifyAll() для этого метода, или пока не истечет указанный промежуток времени.
- void finalize() - вызывается сборщиком мусора, когда garbage collector определил, что ссылок на объект больше нет.
метод equals()
это метод класса Object, который используется для сравнения объектов на предмет логического равенства
метод hashCode()
Это метод класса Object, который возвращает целочисленное значение (хэш-код) объекта.
Хэш-код используется в таких структурах данных, как HashMap, HashSet и HashTable для более быстрого поиска объектов.
Как работает метод equals() по умолчанию?
По умолчанию метод equals() в классе Object сравнивает ссылки (адреса в памяти) объектов. Если объекты указывают на один и тот же адрес в памяти, возвращается true, иначе — false.
Как работает метод hashCode() по умолчанию?
Метод hashCode() по умолчанию возвращает уникальное целочисленное значение, основанное на внутреннем представлении адреса объекта в памяти.
Зачем переопределять метод equals()?
Метод equals() переопределяют, чтобы сравнивать объекты по логическому содержимому (состоянию), а не по их адресам в памяти. Это полезно, когда нужно определить эквивалентность объектов на основе их полей.
Зачем переопределять метод hashCode()?
Переопределение hashCode() необходимо, если вы переопределили equals().
Это делается для того, чтобы объекты, которые считаются равными по методу equals(), имели одинаковый хэш-код, иначе структуры данных на основе хэширования будут работать неправильно.
Какие контракты должны выполняться при переопределении equals() и hashCode()?
- Рефлексивность: объект должен быть равен самому себе.
- Симметричность: если a.equals(b) возвращает true, то и b.equals(a) должно вернуть true.
- Транзитивность: если a.equals(b) и b.equals(c), то a.equals(c) должно также вернуть true.
- Непротиворечивость: если объекты не изменяются, многократные вызовы equals() должны возвращать одинаковое значение.
- Связь с hashCode(): если два объекта равны согласно equals(), то их хэш-коды также должны быть равны.
Что произойдет, если переопределить equals(), но не переопределить hashCode()?
Если переопределить только equals(), но не переопределить hashCode(), то объекты, которые равны по equals(), могут иметь разные хэш-коды.
Это нарушит контракт между equals() и hashCode(), что приведет к ошибкам при работе с хэш-таблицами (например, HashMap, HashSet).
Как правильно переопределить hashCode()?
Метод hashCode() должен быть согласован с equals().
Для этого обычно используют все поля объекта, участвующие в сравнении в методе equals().
Это можно сделать с помощью умножения хэш-кодов полей на простые числа для уменьшения коллизий.
Что такое “коллизия хэш-кодов”?
Коллизия хэш-кодов возникает, когда два различных объекта имеют одинаковый хэш-код. Это неизбежно в хэш-структурах данных, и их нужно минимизировать, но не полностью исключить.
Почему важно минимизировать коллизии хэш-кодов?
Частые коллизии могут снижать производительность хэш-структур, так как они приводят к тому, что несколько объектов помещаются в одну корзину (bucket), и тогда они должны быть дополнительно проверены с помощью метода equals().
Что такое консистентность между equals() и hashCode()?
Консистентность между этими методами означает, что если два объекта равны по equals(), то их хэш-коды тоже должны быть равны.
Это важно для корректной работы объектов в хэш-структурах данных.
Что произойдет, если два объекта имеют одинаковый хэш-код, но не равны по equals()?
Такая ситуация допустима. Однако при вставке в хэш-структуру может произойти коллизия, и тогда будет использован метод equals() для точной проверки на равенство.
Может ли метод hashCode() вернуть отрицательное значение?
Да, метод hashCode() может возвращать отрицательные значения. Это допустимо, поскольку хэш-код является целым числом.
Какова связь между equals() и сравнением по ссылке (оператором ==)?
Оператор == сравнивает ссылки на объекты, т.е. проверяет, указывают ли переменные на один и тот же объект в памяти.
Метод equals(), в свою очередь, можно переопределить для логического сравнения содержимого объектов, а не их адресов в памяти.
В каких случаях лучше использовать instanceof для проверки типа в equals()?
instanceof полезен, если классы, между которыми происходит сравнение, могут быть связаны через наследование.
Например, если класс является частью иерархии и требуется сравнивать объекты не только одного класса, но и его наследников.
Что такое “рассеивание” хэш-кодов?
Рассеивание хэш-кодов — это процесс, при котором значения хэш-кодов равномерно распределяются по диапазону возможных значений. Хорошее рассеивание хэш-кодов важно для уменьшения коллизий и повышения производительности хэш-структур.
Какие особенности нужно учитывать при работе с equals() и hashCode() в многопоточной среде?
В многопоточной среде важно, чтобы объект оставался неизменяемым или безопасно изменяемым, если он используется в хэш-структурах.
Изменение состояния объекта (а значит, и хэш-кода) в одном потоке может привести к некорректной работе с объектом в другом потоке.