Допустим, я реализую класс Car, с 2 переменными-членами int numDoors и цветом String.
В гипотетическом случае я никогда не буду использовать такой автомобиль в хэш-таблице или хэшмапе или любой структуре, которая нуждается в хеше, незапамятных времен.
Теперь, почему все еще требуется переопределить hashCode вместе с равными?
Примечание: все ответы, которые я проверяю, включают использование в hashtable/hashmap. Я пробовал экстенсивно, чтобы получить этот ответ, так как запрос не помещает его как дубликат. благодаря
Если два объекта равны в соответствии с методом
equals(Object)
, то вызов методаhashCode
для каждого из двух объектов должен давать одинаковый целочисленный результат.
Однако это не полностью выполнимо.
Бывают моменты, когда вы считаете, что вам не нужно определять hashCode
и реализовывать его для вашего объекта, и если вы не используете какую-либо структуру, которая полагается на хеш для хранения или ссылки на нее, вы были бы правы.
Но есть сторонние библиотеки, в которых ваш объект может соприкасаться, и они вполне могут использовать Map
или Set
чтобы выполнять свою работу, и у них было бы ожидание, что вы следовали правилам.
Вам не нужно реализовывать hashCode
вместе с equals
- вы, разумеется, не вынуждены (хотя многие утверждают, что это ошибка), но остерегайтесь того, что ваш объект может не работать также с сторонней библиотекой по этой причине.
equals
и не может определить что-либо еще полезное для возврата hashCode()
должен позволить ему вернуть значение identityHashCode()
а не возвращать константу [, которая привела бы к правильному поведению, даже если это не так очень эффективное поведение]
Единственные мыслимые типы, которые не смогли бы переопределить метод hashCode
в соответствии с hashCode
и equals
контракту, были бы теми, которые не могут переопределить hashCode
[например, потому что базовый класс объявил это final
]. Таким образом, почти никогда не существует никаких причин для типа, чтобы не законно реализовать hashCode()
. Даже если тип не может гарантировать, что экземпляры, которые являются неравными, не будут спонтанно становиться равными, автор этого типа может все же законно реализовать hashCode()
, выбрав 32-значное значение int
[например, 8675309] и реализуя hashCode()
как @override int hashCode() { return 8675309; }
@override int hashCode() { return 8675309; }
. Это позволит всем функциям коллекции на основе хэш-таблицы работать правильно. Хранение очень многих таких элементов в хеш-таблице приведет к серьезному ухудшению производительности, но таблицы хэша с несколькими элементами будут работать очень хорошо и обычно выполнять прилично. В отличие от этого, если вы не переопределите hashCode
тогда даже хэш-таблица, скорее всего, будет работать некорректно, если в нее будет сохранен один элемент.
Кстати, в некоторых случаях могут быть преимущества для реализации hashCode
даже если они не используют хешированные коллекции. Например, некоторые неизменные типы коллекций, которые поддерживают глубокое сравнение, могут вызывать hashCode()
для элементов, хранящихся в нем. Если коллекция велика и/или операции сравнения на элементах, хранящихся в ней, являются дорогостоящими, эффективность тестирования двух коллекций для равенства ("они содержат одинаковые элементы") может быть усилена с помощью трехэтапного процесса:
Сравните совокупный хэш-код из двух коллекций. Если они не равны, нет причин смотреть дальше. Часто будет давать мгновенные результаты, независимо от размера коллекций.
Сравните кэшированные хэш-коды всех элементов. Если содержимое коллекций совпадает, за исключением последних элементов пары, и если сравнение между элементами может быть дорогостоящим (например, элементы представляют собой строки с тысячами символов), это часто исключает необходимость сравнивать все, кроме одного элемента, для равенства [обратите внимание, что если все, кроме одного элемента, совпадают, а его хэш-код отличается, то общий хеш-код будет отличаться, и мы бы не получили этого].
Если все хэш-коды совпадают, тогда вызывается equals
для каждой пары элементов, которые не сравниваются с эталонными.
Обратите внимание: если в двух коллекциях содержатся отдельные элементы с одинаковым содержимым, сравнение должно будет глубоко изучить все предметы; hashCode
не может ничего сделать, чтобы помочь в этом случае. С другой стороны, в большинстве случаев, когда вещи сравниваются, они не равны, и использование кешированных значений hashCode()
может способствовать ускорению заказов по величине в этих случаях.
Comparable
если вы никогда не собираетесь сортироватьCars
. И вы можете захотеть переопределитьtoString()
потому что это облегчает запись вещей.