#java
#java
Вопрос:
В моей реализации у меня есть класс A, который переопределяет equals (Object) и hashCode(). Но у меня есть небольшое сомнение в том, что при добавлении экземпляра A в HashSet / HashMap значение hashCode() равно x, через некоторое время значение того же hashCode() изменилось на y. Повлияет ли это на что-нибудь?
Ответ №1:
Хэш-код не должен меняться после того, как он был добавлен в карту / набор. Это нормально, если он изменяется до этого, хотя обычно это упрощает работу с типом, если он не меняется.
Если хэш-код изменится, ключ не будет найден на карте / наборе, поскольку, даже если он окажется в том же сегменте, хэш-код будет изменен первым.
Ответ №2:
Когда возвращаемое значение hashCode()
или equals()
изменяется, пока объект содержится в HashMap
/ HashSet
и т.д., Поведение не определено (вы можете получить все виды странного поведения). Поэтому следует избегать такой мутации ключей, пока объект содержится в таких коллекциях и т.д.
Считается лучшим использовать только неизменяемые объекты для ключей (или размещать их в HashSet
и т.д.). На самом деле, например, python не разрешает использовать изменяемые объекты в качестве ключей в картах. В Java разрешено / распространено использовать изменяемые объекты в качестве ключей, но в таком случае желательно сделать такие объекты «эффективно неизменяемыми». Т.е. вообще не изменять состояние таких объектов после создания экземпляра.
Чтобы привести пример, использование списка в качестве ключа в Map обычно считается допустимым, но вам следует избегать изменения таких списков в любой точке вашего приложения, чтобы избежать появления неприятных ошибок.
Пока вы не измените возвращаемое значение hashCode()
и equals()
, пока объекты находятся в контейнере, на бумаге все должно быть в порядке. Но можно легко ввести неприятные, трудно обнаруживаемые ошибки по ошибке, поэтому лучше вообще избегать ситуации.
Комментарии:
1. 1 за упоминание, что мы говорим о ключе, а не о значении. Хэш-код объекта value может измениться.
Ответ №3:
Да, хэш-код объекта не должен меняться в течение его срока службы. Если это так, вам нужно уведомить контейнер (если это возможно); в противном случае вы будет ли может привести к неправильным результатам.
Редактировать: Как уже указывалось, это зависит от контейнера. Очевидно, что если контейнер никогда не использует ваши методы hashCode
или equals
, ничего не пойдет не так. Но как только он попытается сравнить вещи на предмет равенства (все карты и наборы), у вас возникнут проблемы.
Комментарии:
1. Есть ли какой-либо способ уведомлять об изменении содержимого в HashSet / HashMap?
2. @Jessu: Нет, не в Java HashSet / HashMap. Вам нужно было бы удалить объект, изменить его хэш-код, затем добавить его обратно.
3. Хэш-код может изменяться в течение срока службы объекта — просто, если он уже был добавлен на карту / набор, у вас возникнут проблемы. Можно (скажем) создать ArrayList, добавить в него элементы, а затем использовать это как ключ в HashMap при условии, что впоследствии он никогда не менялся .
4. @Mehrdad: Это указано в вопросе (совсем не подразумевается), но ваш ответ слишком широкий. Ваш ответ предполагает, что только неизменяемые типы вообще должны переопределять hashCode. Вам нужно быть гораздо более осторожным с изменяемыми типами, которые переопределяют hashCode, и понимать последствия этого, но это допустимо и не нарушает правил в Javadoc.
5. @Mehrdad @JonSkeet: фактическое правило таково: «Всякий раз, когда он вызывается для одного и того же объекта более одного раза во время выполнения Java-приложения, метод hashCode должен последовательно возвращать одно и то же целое число при условии, что никакая информация, используемая в сравнениях equals для объекта, не изменена. ‘ Javadoc для Object.hashCode().
Ответ №4:
ДА. Многие люди ответили на этот вопрос здесь, я просто хочу привести аналогию. Хэш-код — это что-то вроде адреса в коллекции на основе хэша:
Представьте, что вы регистрируетесь в отеле под своим именем «Майк», после этого вы меняете свое имя на «ГрейтМайк» на чековой бумаге. Затем, когда кто-то ищет вас по вашему имени «Майк», он больше не может вас найти.