Статья была выбрана 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, вы всегда сможете найти то, что вас интересует
Ставьте лайки, если считаете это полезным, ваши лайки — самая большая мотивация для моего творчества.~
Я программист, который изо всех сил старается запомниться. Увидимся в следующий раз! ! !
Возможности ограничены, если есть какие-то ошибки или неуместности, просьба критиковать и исправлять их, учиться и обмениваться вместе!