Что такое лучшая практика записи хеш-функции в Java?

Я задаюсь вопросом, какова лучшая практика для записи #hashCode () метод в Java. Хорошее описание может быть найдено здесь. Это настолько хорошо?

38
задан Denys S. 29 April 2010 в 16:10
поделиться

3 ответа

Отличный справочник по реализации hashCode () описан в книге Эффективная Java . После того, как вы поймете теорию создания хорошей хеш-функции, вы можете проверить HashCodeBuilder на Apache commons lang, который реализует то, что описано в книге. Из документации:

Этот класс позволяет создать хороший метод hashCode для любого класса. Он следует правилам, изложенным в книге Эффективная Java Джошуа Блоха. Написать хороший метод hashCode на самом деле довольно сложно. Этот класс призван упростить процесс.

23
ответ дан 27 November 2019 в 03:29
поделиться

Как говорит @leonbloy, хорошо это понимать. Однако даже в этом случае один из «лучших» способов - просто позволить вашей среде IDE написать функцию за вас. Это не будет оптимальным при некоторых обстоятельствах - а в некоторых очень редких случаях это даже не будет хорошо - но для большинства ситуаций это легко, повторяемо, без ошибок и настолько хорошо (как хэш-код), насколько это необходимо. быть. Конечно, прочтите документацию и хорошо ее поймите, но не усложняйте ее без необходимости.

0
ответ дан 27 November 2019 в 03:29
поделиться

Вот цитата из Effective Java 2nd Edition, Item 9: "Always override hashCode when you override equals":

Хотя рецепт в этом пункте дает достаточно хорошие хэш-функции, он не дает современных хэш-функций, и библиотеки платформы Java не предоставляют таких хэш-функций по состоянию на релиз 1.6. Написание таких хэш-функций - это тема для исследований, которую лучше оставить математикам и компьютерным ученым. [... Тем не менее,] техники, описанные в этом пункте, должны быть достаточными для большинства приложений".

Рецепт Джоша Блоха

  • Храните некоторое постоянное ненулевое значение, скажем 17, в переменной int под названием result
  • Вычислите хэш-код int c для каждого поля f, которое определяет equals:
    • Если поле является булевым, вычислите (f ? 1 : 0)
    • Если поле является byte, char, short, int, вычисляем (int) f
    • Если поле является long, вычисляем (int) (f ^ (f >>> 32))
    • Если поле является float, вычисляем Float. floatToIntBits(f)
    • Если поле является double, вычислите Double. doubleToLongBits(f), затем хэшируйте полученный long, как указано выше
    • Если поле является объектной ссылкой и метод этого класса equals сравнивает поле, рекурсивно вызывая equals, рекурсивно вызывайте hashCode для поля. Если значение поля равно null, верните 0
    • Если поле является массивом, обращайтесь с ним так, как будто каждый элемент является отдельным полем. Если каждый элемент поля массива значим, можно использовать один из методов Arrays.hashCode, добавленных в релизе 1.5
  • Объедините хэш-код c в result следующим образом: result = 31 * result + c;

Теперь, конечно, этот рецепт довольно сложен, но, к счастью, вам не придется каждый раз реализовывать его заново, благодаря java.util.Arrays.hashCode(Object[]).

@Override public int hashCode() {
    return Arrays.hashCode(new Object[] {
           myInt,    //auto-boxed
           myDouble, //auto-boxed
           myString,
    });
}

Начиная с Java 7 есть удобный вариант varargs в java.util.Objects.hash(Object...).

54
ответ дан 27 November 2019 в 03:29
поделиться
Другие вопросы по тегам:

Похожие вопросы: