В данной статье хотелось бы отобразить контракт перекрытия самых распространенных методов, которые принимают активное участие в поиске объекта по маппам.
Часто на собеседовании (особенно начинающие разработчики) слышат вопрос: "А расскажите мне, что такое контракт между equals() и hashCode()?". Тут хотелось бы отметить, что контракт не конкретно между ними, и вообще под понятие контракт тут понимается общие правила, которым надо следовать для корректной работы с объектами в будущем, а не только между 2 методами. Давайте разберем эти методы подробнее.
Как говориться - самый простой способ избежать проблем это не перекрывать метод equals() вовсе. Но если по ряду причин вы принимаете такое решение, то тут надо ПРИДЕРЖИВАТЬСЯ ОБЩЕГО КОНТРАКТА В СПЕЦИФИКАЦИИ Object:
- Рефлексивность - x.equals(x) возвращает true (для любой ненулевой ссылки на x)
- Симметричность - если y.equals(x) равно true то и x.equals(y) тоже должен возвращать true (для любых ненулевых ссылок на x и y)
- Транзитивность - если x.equals(y) равно true и y.equals(z) тоже равно true, то x.equals(z) тоже должно равняться true (для любых ненулевых ссылок на x, y, z)
- Непротиворечивость - многократные вызовы x.equals(y) должны постоянно возвращать одно и тоже значение (либо true, либо false) (для любых ненулевых ссылок на x и y)
- Неналовость - для ненулевой ссылки на x выражение x.equals(null) должно возвращать false
Попробуйте вчитаться в данные правила несколько раз. На самом деле они очень логичны и просто просят пользователя API делать так, чтобы каждый экземпляр класса был равен сам себе.
Что касаемо перекрытия hashCode() - то тут правила немного сложнее, но со временем тоже становяться очевидными.
- Перекрывайте hashCode() везде, где перекрываете equals() - если не следовать данному требованию контракта, то класс не сможет корректно работать с коллекциями (HashMap или HashSet).
- Многократный вызов метода hashCode() должен возвращать всегда одно и то же целое число, если никакая информация этого объекта не изменилась (при одном выполнении приложения - при разных запусках hashCode() может меняться)
- Если 2 объекта равны при сравнении через метод equals(), то для каждого из этих объектов hashCode() должен вернуть одинаковые значения
- Если 2 объекта не равны при сравнении через метод equals(), то это не гарантирует, что метод hashCode() вернет разные значения для этих объектов (но для улучшения производительности хеш-таблиц лучше писать метод hashCode() так, чтобы он возвращал разные значения для разных объектов)
Если коротко, то вот весь контракт между двумя этими методами. Более детально и с примерами, рекомендую ознакомиться с документацией на методы класса Object. Всем чистого кода!