Любопытное поведение хэш-кода Java с повторяющимися положительными и отрицательными двойникамиJAVA

Программисты JAVA общаются здесь
Ответить
Anonymous
 Любопытное поведение хэш-кода Java с повторяющимися положительными и отрицательными двойниками

Сообщение Anonymous »

У меня было немного любопытное поведение с отрицательными и положительными хеш-кодами с двойным значением, которого я не ожидал. По сути, если одно и то же значение Double появляется дважды в функции хэш-кода, если знак этого Double меняется (posneg), хеш-код остается прежним. Например:

Код: Выделить всё

public final int hashCode() {
int result = ...
result = 31 * result + netAmount.hashCode();
result = 31 * result + grossAmount.hashCode();
...
return result;
}
Используя jshell и просматривая двоичный код хэш-кода, имеет смысл, что если вы умножите на 2, вы получите то же значение:

Код: Выделить всё

Double.valueOf("460.4").hashCode() = 639279104
Double.valueOf("-460.4").hashCode() = -1508204544

Double.valueOf("460.4").hashCode() * 2 = 1278558208
Double.valueOf("-460.4").hashCode() * 2 = 1278558208
Хорошо, это имеет смысл. Но в моей функции хэш-кода я умножаю на 31 после каждого шага, чтобы это предотвратить? Возможно, нет. Преобразование моей функции хэш-кода в однострочный:

Код: Выделить всё

31 * (123 + Double.valueOf("460.4").hashCode()) + Double.valueOf("460.4").hashCode() = -1017901339
31 * (123 + Double.valueOf("-460.4").hashCode()) + Double.valueOf("-460.4").hashCode() = -1017901339
И если я проделаю математические действия, мы увидим, что это будет:

Код: Выделить всё

31*123 + 32*Double.valueOf("460.4").hashCode() = -1017901339
31*123 + 32*Double.valueOf("-460.4").hashCode() = -1017901339
Итак, 32 здесь имеет тот же эффект битового сдвига, что означает, что положительное двойное значение оказывается таким же, как и отрицательное. Дикие!
Что мне здесь делать, чтобы предотвратить эти столкновения? Просто использовать 37 или какое-то другое число? Добавление хэш-кода сигнума двойника к результату?
edit: Для пояснения: «один лайнер» - это я пытаюсь собрать все строки воедино. в функции hashCode. По сути:

Код: Выделить всё

public final int hashCode() {
int result = 123
result = 31 * result + Double.valueOf("460.4").hashCode();
result = 31 * result + Double.valueOf("460.4").hashCode();
return result;
}
Сделайте это для положительного или отрицательного двойного значения 460,4, и результат будет тот же.
Окончательное редактирование: I меня убедили в любом случае не использовать реализацию hashCode() по умолчанию и использовать что-то вроде хеша Murmur. Не из-за конфликтов, а потому, что я не осознавал, что нет никаких гарантий, что hashcode() вернет одно и то же значение при запуске приложения или даже при обновлении версии jvm. Спасибо за все ответы!

Подробнее здесь: https://stackoverflow.com/questions/790 ... ve-doubles
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «JAVA»