Переопределение метода hashCode в Java

    Команда Simple-Server
    03.06.2026
    7 мин

    Материал подготовлен командой Simple-Server для администраторов VPS и выделенных серверов. Команды и пути проверяйте на тестовой машине перед production.

    Требования к реализации метода hashCode()

    Объявление метода hashCode() выглядит следующим образом:

    public int hashCode() { // ... }

    Для правильной реализации рассматриваемого метода в Java определен список следующих требований:

    • Во-первых, если вызов метода hashCode() выполняется неоднократно над одним и тем же объектом, то во всех случаях он должен возвращать одинаковое значение, учитывая, что над полями этого объекта не выполнялись какие-либо изменения.
    • Во-вторых, если вызов рассматриваемого метода выполняется над двумя равнозначными объектами, тогда он обязан возвращать одинаковый результат для обоих. Равенство таких объектов можно проверить благодаря методу equals(). Он должен вернуть true, если сравниваемые объекты равны.
    • И наконец, если возвращаемые результаты при вызове метода для двух объектов одинаковы, то это не гарантирует их равенства. Если они разные, то это гарантирует, что объекты не равны.

    Представленные выше требования говорят о важности использования рассматриваемого метода вместе с equals() для сравнения объектов. Второй выполняет сравнение объектов, а первый в свою очередь показывает, изменилось ли состояние объекта. Это еще раз подтверждает, что при переопределении метода equals() нужно не забывать про переопределение hashCode().

    Переопределение метода hashCode()

    Первое, что придет в голову пользователю, который захочет выполнить переопределение hashCode() в Java, – это сделать возвращение константы:

    @Override public int hashCode() { return 7; }

    Реализовывать переопределение подобным образом категорически нельзя, и на это есть свои причины:

    1. Данный пример реализации переопределения метода удовлетворяет требованиям и вернет одинаковое число для двух равных объектов, но в случае изменения состояния одного из них, его хэш-код не будет изменен. А это уже не соответствует требованиям, описанным выше.
    2. При подобной реализации возникновение коллизий гарантировано.

    Исходя из вышеперечисленных недостатков, от подобного переопределения метода необходимо отказаться.

    Существует два варианта правильного**** переопределения метода hashCode() в Java:

    1. Использование существующего алгоритма для собственной реализации переопределения.
    2. Использование вспомогательных методов для генерации хэш-кода.

    Первый вариант предполагает выполнение следующих правил для переопределения hashCode() в Java:

    1. Во-первых, необходимо исключить все избыточные поля, которые не участвуют в equals().
    2. Во-вторых, следует выбрать базу — стартовое число, необходимое для расчета hash-кода объекта и присвоить его переменной total. Зачастую разработчики берут число 31, но вы можете выбрать иное значение. Многие IDE выполняют генерацию хэш-кода именно с этим числом.
    3. Далее для каждого из оставшихся полей после исключения проводится расчет хэша. Ниже будет приведена таблица правил вычисления для возможных типов полей:
    Тип поляПравило
    boolean(f ? 1 : 0)
    char, short, byte или int(int) f
    floatFloat.floatToIntBits(f)
    doubleDouble.doubleToLongBits(f), а затем (int)(f ^ (f >>> 32))
    long(int)(f ^ (f >>> 32))
    Ссылка на другой объектРекурсивный вывод метода hashCode()
    МассивОбработать каждый элемент массива, как отдельное поле объекта
    nullreturn 0

    char, short, byte или int

    Double.doubleToLongBits(f), а затем (int)(f ^ (f >>> 32))

    Рекурсивный вывод метода hashCode()

    Обработать каждый элемент массива, как отдельное поле объекта

    1. Следующее правило гласит, что нужно прибавить рассчитанный хэш каждого из полей (допустим, это переменная compute) к переменной total:
    total = 31 * total + compute;
    1. И наконец, необходимо вернуть итоговое значение переменной total после выполнения всех расчетов.

    Приведем пример реализации переопределения метода для класса Staff, используя перечисленные выше правила:

    public class Staff { private String FCs; private String city; private int experience; private double wage; private String department; public Staff(String FCs, String city, int experience, double wage, String department) { this.FCs = FCs; this.city = city; this.experience = experience; this.wage = wage; this.department = department; } @Override public int hashCode() { int total = 31;  total = total * 31 + (FCs == null ? 0 : FCs.hashCode());  total = total * 31 + (city == null ? 0 : city.hashCode());  total = total * 31 + experience;  long lwage = Double.doubleToLongBits(wage);  total = total * 31 + (int)(lwage ^ (lwage >>> 32));  total = total * 31 + (department == null ? 0 : department.hashCode());  return total;  } // Переопределение equals() // ... }

    Аннотация @Override перед объявлением рассматриваемого метода проверяет, что переопределяемый метод есть в родительском классе.

    Все строковые поля (FCs, city, и department) проверяются на null перед вызовом их метода hashCode(), чтобы обеспечить безопасность от NullPointerException.

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

    @Override public int hashCode() { return Objects.hash(FCs, city, experience, department); }

    У всех стандартных ссылочных типов данных в Java (String, Integer, Double и т. д.) методы equals() и hashCode() уже корректно переопределены. Поэтому их возможно спокойно интегрировать в коллекции HashMap, HashSet и другие.


    Нужен сервер для практики? Арендуйте VPS/VDS в России — root-доступ, NVMe, DDoS-защита и поддержка 24/7.

    VPS для проекта

    VPS с root-доступом, NVMe и поддержкой 24/7 на Simple-Server.

    StarterVDS

    490

    в месяц

    1 ядро

    1 ГБ RAM

    20 ГБ NVMe

    • 1 IPv4
    • KVM
    • Root-доступ
    • Безлимитный трафик
    Заказать VPS
    Рекомендуем

    PerformanceVDS

    1190

    в месяц

    2 ядра

    4 ГБ RAM

    60 ГБ NVMe

    • 1 IPv4
    • KVM
    • Root-доступ
    • Базовая DDoS-защита
    Заказать VPS

    Нужна другая конфигурация или чистый VPS без панели?

    Все тарифы VPS

    Похожие статьи, которые могут быть вам интересны