Подтвердить что ты не робот

В чем причина Enum.hashCode()?

Метод hashCode() в классе Enum является окончательным и определяется как super.hashCode(), что означает, что он возвращает число, основанное на адресе экземпляра, который является случайным числом от программистов POV.

Определение его, например. поскольку ordinal() ^ getClass().getName().hashCode() будет детерминированным для разных JVM. Это даже улучшилось бы, так как наименее значимые биты "как можно больше менялись", например, для перечисления, содержащего до 16 элементов и HashMap размером 16, не было бы никаких столкновений (конечно, использование EnumMap лучше, но иногда невозможно, например, нет ConcurrentEnumMap). С текущим определением у вас нет такой гарантии, не так ли?

Резюме ответов

Использование Object.hashCode() сравнивается с более приятным хэш-кодом, как показано выше:

  • ПРОФИ
    • Простота
  • контрас
    • скорость
    • больше коллизий (для любого размера HashMap)
    • недетерминизм, который распространяется на другие объекты, делая их непригодными для
      • детерминированные симуляции
      • Расчет ETag
      • поиск ошибок в зависимости, например. по порядку итерации HashSet

Я лично предпочел бы более приятный hashCode, но IMHO не имеет большой вес, возможно, за исключением скорости.

UPDATE

Мне было интересно узнать скорость и написал benchmark с удивительным результаты. По цене одного поля за класс вы можете детерминировать хэш-код, который почти в четыре раза быстрее. Хранение хеш-кода в каждом поле будет еще быстрее, хотя и пренебрежимо.

Объяснение, почему стандартный хэш-код не намного быстрее, заключается в том, что он не может быть адресом объекта, поскольку объекты передаются GC.

ОБНОВЛЕНИЕ 2

Есть некоторые странные вещи с показателем hashCode в целом. Когда я их понимаю, все еще остается открытым вопрос, почему System.identityHashCode (чтение из заголовка объекта) работает медленнее, чем доступ к нормальному объекту.

4b9b3361

Ответ 1

Я думаю, что причина, по которой они сделали это окончательное, - избегать разработчиков, стреляющих в ногу, переписывая субоптимальный (или даже неверный) хэш-код.

Что касается выбранной реализации: она нестабильна в JVM, но очень быстро, избегает коллизий и не нуждается в дополнительном поле в перечислении. Учитывая обычно небольшое количество экземпляров класса enum и скорость метода equals, я бы не удивился, если бы время поиска HashMap было больше с вашим алгоритмом, чем с текущим, из-за его дополнительной сложности.

Ответ 2

Единственная причина использования Object hashCode() и для того, чтобы сделать его окончательным, я могу себе представить, чтобы я задал этот вопрос.

Прежде всего, вы не должны полагаться на такие механизмы для совместного использования объектов между JVM. Это просто не поддерживается. При сериализации/десериализации вы должны полагаться на свои собственные механизмы сравнения или только "сравнивать" результаты с объектами в вашей собственной JVM.

Причина того, что enums hashCode будет реализована как хэш-код Objects (на основе идентификации), заключается в том, что внутри одной JVM будет только один экземпляр каждого объекта перечисления. Этого достаточно, чтобы гарантировать, что такая реализация имеет смысл и правильна.

Вы можете утверждать, что "Hey, String и обертки для примитивов (Long, Integer,...) имеют четко определенные, детерминированные спецификации hashCode! Почему нет перечислений?", Начнем с того, что у вас может быть несколько различных строковых ссылок, представляющих одну и ту же строку, что означает, что использование super.hashCode будет ошибкой, поэтому этим классам обязательно понадобятся собственные реализации hashCode. Для этих основных классов имело смысл дать им хорошо определенные детерминированные хэш-коды.

Почему они решили решить это так?

Хорошо, посмотрите требования реализации hashCode. Основная проблема заключается в том, чтобы каждый объект должен возвращать отдельный хеш-код (если он не равен другому объекту). Подход, основанный на идентификации, является суперэффективным и гарантирует это, в то время как вашего предложения нет. Это требование, по-видимому, более сильное, чем любой "удобный бонус" об ослаблении сериализации и т.д.

Ответ 3

Я задал тот же вопрос, потому что не видел этого. Почему в Enum hashCode() ссылается на реализацию объекта hashCode(), а не на функцию ordinal()?

Я столкнулся с этим как своего рода проблема при определении моей собственной хеш-функции, поскольку объект полагался на enum hashCode как один из композитов. При проверке значения в наборе объектов, возвращаемом функцией, я проверил их в порядке, который я ожидаю, что он будет таким же, поскольку хэш-код я определяю сам, и поэтому я ожидаю, что элементы упадут на одни и те же узлы на дереве, но так как hashCode, возвращаемый перечислением переименования от начала до начала, это предположение было неправильным, и тест мог терпеть неудачу один раз в то время.

Итак, когда я понял проблему, я начал использовать порядковый номер. Я не уверен, что все, кто пишет хэш-код для своего Объекта, понимают это.

В принципе, вы не можете определить свой собственный детерминированный хэш-код, полагаясь на enum hashCode, и вам нужно использовать вместо него порядковый номер

P.S. Это было слишком большим для комментария:)

Ответ 4

JVM устанавливает, что для константы перечисления в памяти будет существовать только один объект. Нет никакого способа, чтобы вы могли получить два разных объекта экземпляра одной и той же константы перечисления в одной виртуальной машине, а не с отражением, а не через сеть с помощью сериализации/десериализации.

Говоря это, поскольку это единственный объект для представления этой константы, не имеет значения, что его hascode является его адресом, поскольку ни один другой объект не может занимать одно и то же адресное пространство одновременно. Он гарантированно будет уникальным и "детерминированным" (в том смысле, что в той же VM в памяти все объекты будут иметь одну и ту же ссылку, независимо от того, что это такое).

Ответ 5

Пока мы не можем отправить объект перечисления 1 в другую JVM, я не вижу причин для установки таких требований для перечислений (и объектов вообще)


1 Я думал, что это достаточно ясно - объект - это экземпляр класса. Серийный объект - это последовательность байтов, обычно хранящихся в массиве байтов. Я говорил об объекте.

Ответ 6

Нет необходимости, чтобы хэш-коды были детерминированными между JVM и не получили преимуществ, если бы они были. Если вы полагаетесь на этот факт, вы используете их неправильно.

Поскольку существует только один экземпляр каждого значения перечисления, Object.hashcode() гарантируется никогда не сталкиваться, это хорошее повторное использование кода и очень быстро.

Если равенство определено тождеством, то Object.hashcode() всегда будет давать лучшую производительность.

Детерминизм других хэш-кодов является лишь побочным эффектом их реализации. Поскольку их равенство обычно определяется значениями полей, смешение в недетерминированных значениях было бы пустой тратой времени.

Ответ 7

Еще одна причина, по которой это реализовано, как я мог себе представить, - это требование, согласно которому hashCode() и equals() должны быть согласованными, а также для целей проектирования Enums, что они могут быть просты в использовании и времени компиляции constant (использовать их - "случайные" константы). Это также позволяет законно сравнивать экземпляры enum с "==", и вы просто не хотите, чтобы "равно" вел себя неравномерно от "==" для перечислений. Это снова связывает hashCode с поведением Object.hashCode() по умолчанию по умолчанию. Как было сказано ранее, я также не ожидаю, что equals() и hashCode() рассмотрят две константы перечислителя из разных JVM как равные. Когда речь идет о сериализации: например, поля, введенные как перечисления, бинарный сериализатор по умолчанию в Java имеет особое поведение, которое сериализует только имя константы, а при десериализации восстанавливается ссылка на соответствующее значение перечисления в де-сериализованной JVM, Аналогичным образом работает JAXB и другие механизмы сериализации на основе XML. Итак: просто не волнуйся.