Почему переопределить equals() также переопределить hashCode()

Java

Почему переопределить equals() также переопределить hashCode()

Писательские навыки у автора пока поверхностны, если что не так, укажите великодушно, буду обязательно признателен

существуетEffective Javaохвачено Разделом IXequals()метод всегда переопределяетhashCode()метод. Почему это? Далее мы представим эти два метода.

на Явеequals()Методы иhashCode()методы находятся вObjectметоды в классе, тогда как в Java все классыObejctПодкласс класса, поэтому все методы в Java будут иметь реализацию этих двух методов по умолчанию.

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

Objectв классеequals()Метод определяется следующим образом

1public boolean equals(Object obj) {
2    return (this == obj);
3}

Мы нашлиequals()Ключ==,Так==Что это означает в Java Все мы знаем, что в Java существуют базовые типы данных и ссылочные типы данных. Так==Роль этих двух типов не одинакова.

  • Примитивные типы данных: по сравнению с==Равны ли значения с обеих сторон?
  • Справочные типы данных: по сравнению с==Равны ли адреса памяти с обеих сторон

К основным типам данных относятся:byte,short,char,int,long,float,double,boolean

И через документацию по Javaequals()Описание метода, все реализовать самостоятельноequals()Метод должен соблюдать следующие правила

  • Рефлексивность: для любого объекта xx.equals(x)должен вернутьсяtrue
  • Симметрия: для любых двух объектов x и y, еслиx.equals(y)возвращениеtrue,Такy.equals(x)также должен вернутьсяtrue
  • Транзитивность: для нескольких объектов x, y, z, еслиx.equals(y)возвращениеtrue,y.equals(z)возвращениеtrue,Такy.equals(z)также должен вернутьсяtrue
  • Непротиворечивость: для двух ненулевых объектов x, y результаты, возвращаемые несколькими вызовами, должны быть одинаковыми без изменения объекта.
  • Для любого ненулевого объекта xx.equals(null)должен вернутьсяfalse

метод hashCode

ObjectсерединаhashCode()метод — это нативный метод, который возвращаетintтип хэш-значения.

1public native int hashCode();

существуетhashCode()В методе также есть некоторые условности.

  • если объект используетequalsПараметры для сравнения в методе не изменяются, то вызов объектаhashCode()Хэш-значение, возвращаемое методом, должно быть таким же.
  • если два объекта проходятequalsМетод сравнения равен,Требоватьэти два объектаhashCodeЗначения, возвращаемые методами, также должны быть равны.
  • если два объекта проходятequalsсравнение методов отличается, то иНе требуетэти два объектаhashCodeЗначения, возвращаемые методами, не совпадают. Но мы должны знать, что генерация разных хеш-значений для разных объектов может повысить производительность для хеш-таблиц (HashMap и т. д.).

Где будет использоваться метод equals и метод hashCode

В каком классе Java часто встречаются эти два метода? Если вы виделиHashMapИсходный код должен понимать, что эти два метода часто появляются вHashMapсередина. Онлайн-введениеHashMapВ этой категории много статей, вот краткое введениеHashMap.

Когда связанный список в узле превышает 8, он становится красно-черным деревом, чтобы устранить недостаток медленной скорости запросов после того, как длина связанного списка станет слишком большой.

HashMapЭто эффективная структура хранения данных, состоящая из массивов и связанных списков. Так как же определить, где в массиве хранятся данные? черезhashCodeспособ вычислить, где его хранить, помните, что мы сказали вышеhashCodeМетод говорит, что возможно иметь два разных объектаhashCodeЕсли значение, возвращаемое методом, одинаковое, то будет конфликт, а если есть конфликт, то он будет вызванequalsМетоды сравниваются, если они разные, то добавляются в хвост связанного списка, если совпадают, то заменяются исходные данные.

Конечно, расчет позиции не так прост, как описано выше.hashCodeМетод вычисляется, и в середине есть некоторые другие шаги, которые можно просто рассматривать какhashCodeМесто определяется.

Когда переопределить эти два метода?

Если вы не определите свой собственный класс какHashMapЕсли значение ключа , то перепишемequalsМетод без перезаписиhashCodeМетод, компилятор не сообщает об ошибках, во время выполнения не будет генерировать никаких исключений.

Если вы хотите определить свой собственный класс какHashMapКлюч стоит, то если переписатьequalsметод также должен быть переопределенhashCodeметод.

Далее мы можем посмотреть на использование нами пользовательских классов какHashMapключ, и пользовательский класс не переопределяетequalsиhashCodeметод, что происходит.

пользовательский класс

1@Builder
2@NoArgsConstructor
3@AllArgsConstructor
4class CustomizedKey{
5    private Integer id;
6    private String name;
7}

Далее мы рассмотрим использование пользовательского класса в качестве ключа.

 1    public static void main(String[] args) {
2
3        Map<CustomizedKey, Integer> data = getData();
4
5        CustomizedKey key = CustomizedKey.builder().id(1).name("key").build();
6
7        Integer integer = data.get(key);
8
9        System.out.printf(String.valueOf(integer));
10    }
11
12    private static Map<CustomizedKey,Integer> getData(){
13        Map<CustomizedKey,Integer> customizedKeyIntegerMap = new HashMap<>();
14        CustomizedKey key = CustomizedKey.builder().id(1).name("key").build();
15        customizedKeyIntegerMap.put(key,10);
16        return customizedKeyIntegerMap;
17    }

Мы видим, что последнее, что печатает программа, этоnullценность. Причина та же, что мы сказали выше.

  • hashCode: Используется для расчета, где объект размещен в массиве, потому что оба являются новыми объектами, поэтому, даже если значение внутри одинаково, адрес объекта отличается, поэтому используйте по умолчаниюhashCodeразные, конечноhashMapне будет рассматривать их как один объект.

Далее мы перепишем эти два метода. если мы используемIDEAЕсли это так, просто используйте горячие клавиши напрямую.

Далее мы рассмотрим два метода, которые мы реализовали.

 1@Builder
2@NoArgsConstructor
3@AllArgsConstructor
4class CustomizedKey{
5    private Integer id;
6    private String name;
7
8    @Override
9    public boolean equals(Object o) {
10        if (this == o) return true;
11        if (o == null || getClass() != o.getClass()) return false;
12        CustomizedKey that = (CustomizedKey) o;
13        return Objects.equals(id, that.id) &&
14                Objects.equals(name, that.name);
15    }
16
17    @Override
18    public int hashCode() {
19        return Objects.hash(id, name);
20    }
21}

Затем мы снова запускаем указанную выше программу и обнаруживаем, что вывод на печать стал10.

мы также можем использоватьLombokкоторый предоставил@EqualsAndHashCodeАннотации упрощают код

Кодовый адрес этой статьи

Прошлые статьи

Справочная статья