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

Какова наилучшая практика написания хэш-функции в java?

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

4b9b3361

Ответ 1

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

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

Ответ 2

Вот цитата из Effective Java 2nd Edition, Item 9: "Всегда переопределять hashCode когда вы переопределяете equals ":

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

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

  • Сохраните некоторое постоянное ненулевое значение, скажем, 17, в переменной int называется result
  • Вычислить int хеш-код c для каждого поля f которое определяет equals:
    • Если поле является boolean, вычислить (f? 1: 0)
    • Если поле является byte, char, short, int, compute (int) f
    • Если поле long, вычислите (int) (f ^ (f >>> 32))
    • Если поле является float, вычислить Float.floatToIntBits(f)
    • Если поле типа double, вычислите Double.doubleToLongBits(f), а затем 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.

Ответ 3

Да. Но не пропустите концептуальные объяснения и перейдите к примерам кода. Прежде чем знать, как написать метод, вы должны понять, что такое hashcode, - и там это объясняется.

Ответ 4

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