Мне интересно, что лучше всего подходит для написания метода #hashCode() в java. Хорошее описание можно найти здесь. Это хорошо?
Какова наилучшая практика написания хэш-функции в java?
Ответ 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 записать эту функцию для вас. В некоторых случаях это не будет оптимальным - и в некоторых очень редких случаях это будет даже не очень хорошо, но для большинства ситуаций это легко, повторяемо, безошибочно и так же хорошо (как хэш-код) по мере необходимости быть. Конечно, читайте документы и хорошо их понимайте, но не делайте это без необходимости.