Какова лучшая практика написания хеш-функции в Java? - PullRequest
37 голосов
/ 29 апреля 2010

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

Ответы [ 3 ]

52 голосов
/ 30 апреля 2010

Вот цитата из Effective Java 2nd Edition , пункт 9: «Всегда переопределять hashCode при переопределении equals»:

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

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

  • Сохраните некоторое постоянное ненулевое значение, скажем, 17, в переменной int, которая называется result
  • Вычисляет int хеш-код c для каждого поля f, которое определяет equals:
    • Если поле имеет значение boolean, вычислить (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, в java.util.Objects.hash(Object...).

есть удобный вариант varargs.
21 голосов
/ 29 апреля 2010

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

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

0 голосов
/ 29 апреля 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...