Зачем добавлять константу в hashCode ()?

Я новичок в Java и недавно узнал о hashCode(). В статье в Википедии о Java hashCode () есть следующий пример hashCode() метод:

public class Employee {
    int        employeeId;
    String     name;
    Department dept;

    // other methods would be in here

    @Override
    public int hashCode() {
        int hash = 1;
        hash = hash * 17 + employeeId;
        hash = hash * 31 + name.hashCode();
        hash = hash * 13 + (dept == null ? 0 : dept.hashCode());
        return hash;
    }
}

Я понимаю, что умножение на 31 и 13 снижает вероятность столкновения, но я не понимаю, почему hash инициализируется значением 1, а не employeeId. В конце концов, это просто приводит к добавлению 17 * 31 * 13 к hashCode(), что не повлияет на то, равны ли два значения hashCode () или нет.

В статье Блоха «Эффективная Java (второе издание)» есть очень похожий пример в правиле 9 (страницы 47 и 48), но его объяснение этой аддитивной константы для меня довольно загадочно.

Изменить: этот вопрос был отмечен как дубликат вопроса Почему Java hashCode () в String использует 31 в качестве множителя? Это не тот вопрос: он спрашивает, есть ли причина предпочесть число 31 любому другому числу в формуле для hashCode() из String. У меня вопрос: почему во многих примерах hashCode(), которые я нашел в Интернете, к hashCode() всех объектов добавляется одна константа.

Фактически, здесь уместен пример hashCode() из String, потому что в этом примере не добавлена ​​константа. Если добавление 17 * 31 * 13 имеет какой-либо эффект в приведенном выше примере, почему бы не добавить такую ​​константу при вычислении hashCode() из String?


person ExoticSphere    schedule 03.10.2018    source источник
comment
что, если employeeId равен нулю?   -  person Amit Phaltankar    schedule 03.10.2018
comment
то же, что и начиная с int hash = 17 + employeeId;   -  person Scary Wombat    schedule 03.10.2018
comment
Какая часть того, что объяснил Блох, является для вас загадкой?   -  person Andreas    schedule 03.10.2018
comment
Нет причин. Как уже указывалось, это то же самое, что начать с int hash = 17 * employeeId; и затем продолжить, это просто делает код красивым и однородным, и компилятор все равно оптимизирует его, так что это чисто косметический характер.   -  person Mike 'Pomax' Kamermans    schedule 03.10.2018


Ответы (1)


Начало с ненулевого значения теоретически помогает, когда hashCode переполняется или составляет% от не степени двойки, что приводит к тому, что большее количество битов отличается от значений, которые переполняются, по сравнению с теми, которые этого не делают.

Маленькие константы не так эффективны, как большие, но могут использовать меньше байтов и работать быстрее. Например. * 31 быстрее, но может быть не таким эффективным, как * 109.

Разница зависит от вашего варианта использования.

Примечание: даже если у вас есть уникальные хэш-коды, это не гарантирует, что у вас не будет коллизий после того, как номер был использован для выбора сегмента.

person Peter Lawrey    schedule 03.10.2018
comment
Не могли бы вы подробнее рассказать о своем первом предложении? Вы говорите, что смещение хэш-кода на константу приводит к большему разногласию битов при сравнении двух хэш-кодов по модулю некоторого числа, что упрощает проверку того, что они действительно разные? - person ExoticSphere; 03.10.2018
comment
@ExoticSphere: да, если вы добавите константу, это приведет к тому, что больше бит будет отличаться. Хотя константа мала, она умножается на коэффициент, даже если константа большего размера (и коэффициенты) может быть лучше. - person Peter Lawrey; 03.10.2018