Вот цитата из 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.