Что произойдет, если вернуть константу в хэш-код и ложь в равных - PullRequest
0 голосов
/ 05 июля 2019

как работает hashcode или hashmap, если мы переопределим hashcode, который всегда возвращает константу, а переопределенные методы equals возвращают false, как он может идентифицировать точный объект при возврате или удалении? Time Bean забыл о производительности всего этого, мой вопрос, как он мог идентифицировать точный объект, позвольте мне объяснить немного подробнее, у меня есть класс person с двумя полями и переопределенный хеш-код, который возвращает всегда 1, и переопределенный метод equals, который возвращает false , создали 3 объекта, объект 1 - идентификатор 10, имя AAAA, объект 2 - идентификатор 20, имя BBB, объект 3 - идентификатор 30, имя CCC, я добавил все три объекта в hashSet, после чего я удалил объект 2, здесь, как его точное определение объекта (20, BBB)

Ответы [ 2 ]

2 голосов
/ 05 июля 2019

Ну, константный хеш-код действителен и «только» проблема производительности при использовании HashMap / HashSet или другого кода, который использует его для оптимизации сравнения / поиска.

Реализация equals(), которая всегдавозвращает false, однако нарушает контракт равных и приведет к проблемам / неожиданному поведению со многими типами коллекций.

Из JavaDocs equals:

Метод equals реализует отношение эквивалентности для ненулевых ссылок на объекты:

  • Это рефлексивно: для любого ненулевого ссылочного значения x, x.equals (x) должен возвращать true.
  • Симметрично: для любых ненулевых ссылочных значений x и y x.equals (y) должен возвращать true тогда и только тогда, когда y.equals (x) возвращает true.
  • Это транзитивно: для любых ненулевых ссылочных значений x, y и z, если x.equals (y) возвращает true, а y.equals (z) возвращает true, тогда x.equals (z) должен возвращать true.
  • Это согласуется: для любых ненулевых опорных значений x и y, кратных iПризывы x.equals (y) последовательно возвращают true или последовательно возвращают false, при условии что никакая информация, используемая в сравнениях сравнения объектов, не изменяется.
  • Для любого ненулевого ссылочного значения x, x.equals (null)должен вернуть false.

Реализация return false нарушает первое требование.

Из JavaDocs hashcode:

  • Не требуется, чтобы, если два объекта были неравны в соответствии с методом equals (java.lang.Object), то вызов метода hashCode для каждого из двух объектов должен давать разные целочисленные результаты.Тем не менее, программист должен знать, что выдача различных целочисленных результатов для неравных объектов может повысить производительность хеш-таблиц.

Как указано в комментариях @ Mensur Qulami , он все равно может работать правильно с HashMap, если ваша реализация использует сравнение ссылок с == для оптимизации поиска узлов.

С OpenJDK 12 HashMap.getNode (int hash, Object key) :

((k = first.key) == key || (key != null && key.equals(k))))

, поэтому эта реализация проверяет равенство ссылок перед попыткой equals(), но это не гарантируется.

Java-документы для HashMap.get определяют это строго в терминах equals()

Более формально, если эта карта содержит отображение из ключа k взначение v такое, что (key==null ? k==null : key.equals(k)), тогда этот метод возвращает v;в противном случае возвращается null.

(это эквивалентно , если , реализация equals выполняет вышеуказанный контракт, поэтому оптимизация, выполненная OpenJDK, действительна)

1 голос
/ 05 июля 2019

Он все еще может удалить объект, даже если equals возвращает false, потому что == по-прежнему возвращает true (== сравнивает фактическую ссылку на объект и не зависит от реализации equals).

HashSet ультимативно вызывает HAshMap, removeNode, который содержит это сравнение, чтобы увидеть, найдено ли значение.

            if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k))))

Он сравнивает hashCode, который всегда равен константе, а затем сначала использует == для сравнения. Если ключ не тот же объект (т. Е. == является ложным), только тогда equals используется для проверки, равны ли они.

Если вы создадите новый объект с тем же значением, вы никогда не сможете использовать его для удаления значения из набора, но при использовании того же объекта вы все равно можете это сделать из-за ==

...