Основа Java не проста, поговорим о взаимосвязи между hashCode() и equals()

Java
Основа Java не проста, поговорим о взаимосвязи между hashCode() и equals()

Статья была выбрана Github, добро пожаловать в Star:GitHub.com/Yehongqin/Лай…

написать впереди

На самом деле, я давно заметил, что в спецификации разработки Java от Alibaba есть предложение:只要重写 equals,就必须重写 hashCode.

Думаю, многие спросят, почему так называемая知其然知其所以然, относиться к знанию не только знать вывод, но и знать причину.

метод hashCode

Функция метода hashCode() состоит в том, чтобы получить хеш-код и вернуть целое число.

Любой, кто изучал структуру данных, знает, что функция хэш-кода заключается в определении нижнего индекса объекта в хеш-таблице. Например, HashSet и HashMap используют метод hashCode для определения нижнего индекса индекса. Если два объекта возвращают один и тот же хэш-код, это называется «коллизией хэшей».

метод равенства

Функция метода equals() очень проста. Она заключается в том, чтобы определить, равны ли два объекта. Метод equals() определен в классе Object, а родительским классом всех классов является Object, поэтому, если метод equals не переписан, будет вызываться Object Метод equals класса.

Метод equals класса Object использует для сравнения знак "==". Во многих случаях, поскольку знак == сравнивает адреса памяти двух объектов, а не фактическое значение, он не очень хорошо отвечает бизнес-требованиям. Так много раз нам нужно переопределить метод equals, чтобы сравнить, равны ли значения каждой переменной-члена в объекте.

Вот проблема

Переопределяя метод equals(), вы можете сравнить, равны ли два объекта Зачем переписывать метод hashcode()?

Поскольку нижний слой HashSet и HashMap сначала определит, равен ли hashCode объекта при добавлении элементов, и если hashCode равен, для сравнения будет использоваться метод equals(). Другими словами, когда HashSet и HashMap определяют, равны ли два элемента,Первым будет оцениваться hashCode.Если hashCode двух объектов отличается, они не должны быть равны..

Давайте проведем эксперимент, есть класс User, только переопределите метод equals(), а затем поместите его в коллекцию Set для дедупликации.

public class User {

    private String id;

    private String name;

    private Integer age;
    
    public User(String id, String name, Integer age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }
    
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user = (User) o;
        return Objects.equals(id, user.id) &&
            Objects.equals(name, user.name) &&
            Objects.equals(age, user.age);
    }
    
    //getter、setter、toString方法
}

Затем мы циклически создаем 10 объектов User с одинаковыми значениями переменных-членов и, наконец, помещаем их в коллекцию Set для дедупликации.

public static void main(String[] args) {
    List<User> list = new ArrayList<>();
    for (int i = 0; i < 10; i++) {
        User user = new User("1", "张三", 18);
        list.add(user);
    }
    Set<User> set = new HashSet<>(list);
    for (User user : set) {
        System.out.println(user);
    }
    List<User> users = list.stream().distinct().collect(Collectors.toList());
    System.out.println(users);
}

По логике мы рассчитывали провести дедупликацию, оставив только одного пользователя «Чжан Сан», но по факту, поскольку метод hashCode не был переписан, дедупликации не было.

Затем мы переписываем некоторые методы hashCode в классе User и пробуем снова, остальные остаются без изменений.

public class User {
    //其他不变
    
    //重写hashCode方法
    @Override
    public int hashCode() {
        return Objects.hash(id, name, age);
    }
}

Запустите его снова, и результат будет правильным.

Причина в том, что HashSet сначала определит, равен ли hashCode.Если hashCode не равен, он сразу посчитает, что два объекта не равны, и не будет использовать equals() для сравнения. Давайте посмотрим на хэш-коды с переопределением метода hashCode и без него.

Это происходит без переопределения метода hashCode.Хэш-код каждого пользовательского объекта отличается, поэтому HashSet будет думать, что они не равны.

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

Поэтому, когда некоторые люди увидят это, они спросят, совпадают ли хеш-коды, возвращаемые двумя объектами, правильно ли это?должно быть равно?

Ответ не обязательно, потому что HashSet и HashMap будут использовать метод equals() для оценки после определения равенства хэш-кодов.

в общем:

  • Если хэш-коды не равны, два объекта должны быть разными.
  • Хэш-коды равны, два объекта не обязательно одинаковы.
  • Если два объекта одинаковы, хеш-код и значение должны совпадать.

Суммировать

Итак, вернемся к тому, что я сказал в начале,只要重写 equals,就必须重写 hashCode, это очень важная деталь, и если не обращать на нее внимания, легко совершить деловые ошибки.

Особенно иногда мы явно используем HashSet, Different() для дедупликации, но это просто не действует. В этот раз, должны ли мы оглянуться назад и переписать методы equals() и hashCode()?

Так что эта статья написана здесь, спасибо за чтение.

Статьи постоянно обновляются. Wechat ищет «энтузиастов технологии Java», а отправленные технические статьи получают как можно скорее после того, как обращают на них внимание. Статьи классифицируются и включаются в github:github.com/yehongzhi, вы всегда сможете найти то, что вас интересует

Ставьте лайки, если считаете это полезным, ваши лайки — самая большая мотивация для моего творчества.~

Я программист, который изо всех сил старается запомниться. Увидимся в следующий раз! ! !

Возможности ограничены, если есть какие-то ошибки или неуместности, просьба критиковать и исправлять их, учиться и обмениваться вместе!