Какие проблемы следует учитывать при переопределении equals и hashCode в Java?

Какие проблемы / подводные камни следует учитывать при отмене equals и hashCode?

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
617
0
585 816
11
Перейти к ответу Данный вопрос помечен как решенный

Ответы 11

Ответ принят как подходящий

Теория (для языковых юристов и математиков):

equals() (javadoc) должен определять отношение эквивалентности (это должно быть рефлексивный, симметричный и переходный). Кроме того, он должен быть последовательный (если объекты не изменены, он должен продолжать возвращать то же значение). Кроме того, o.equals(null) всегда должен возвращать false.

hashCode() (javadoc) также должен быть последовательный (если объект не изменен с точки зрения equals(), он должен продолжать возвращать то же значение).

связь между двумя методами:

Whenever a.equals(b), then a.hashCode() must be same as b.hashCode().

На практике:

Если вы переопределите одно, вы должны переопределить и другое.

Используйте тот же набор полей, который вы используете для вычисления equals() для вычисления hashCode().

Используйте отличные вспомогательные классы EqualsBuilder и HashCodeBuilder из библиотеки Apache Commons Lang. Пример:

public class Person {
    private String name;
    private int age;
    // ...

    @Override
    public int hashCode() {
        return new HashCodeBuilder(17, 31). // two randomly chosen prime numbers
            // if deriving: appendSuper(super.hashCode()).
            append(name).
            append(age).
            toHashCode();
    }

    @Override
    public boolean equals(Object obj) {
       if (!(obj instanceof Person))
            return false;
        if (obj == this)
            return true;

        Person rhs = (Person) obj;
        return new EqualsBuilder().
            // if deriving: appendSuper(super.equals(obj)).
            append(name, rhs.name).
            append(age, rhs.age).
            isEquals();
    }
}

Также помните:

При использовании основанных на хэшах Коллекция или карта, таких как HashSet, LinkedHashSet, HashMap, Хеш-таблица или WeakHashMap, убедитесь, что hashCode () ключевых объектов, которые вы помещаете в коллекцию, никогда не изменяется, пока объект находится в коллекции. Самый надежный способ гарантировать это - сделать ваши ключи неизменяемыми, который имеет и другие преимущества.

Дополнительный момент о appendSuper (): вы должны использовать его в hashCode () и equals () тогда и только тогда, когда вы хотите унаследовать поведение равенства суперкласса. Например, если вы производите прямо от Object, в этом нет смысла, потому что все объекты по умолчанию различны.

Antti Kissaniemi 28.05.2009 23:03

Особое внимание следует уделять переходным полям.

aviad 12.04.2011 16:36

Отличное обсуждение этого вопроса в книге «Эффективная Java».

K'' 12.08.2011 22:48

Вы можете заставить Eclipse сгенерировать для вас два метода: Source> Generate hashCode () и equals ().

Rok Strniša 22.11.2011 22:58

имеет значение, если мы все случайно выбрали одни и те же простые числа?

zod 12.07.2012 13:10

То же самое и с Netbeans: developmentality.wordpress.com/2010/08/24/…

seinecle 11.08.2012 11:59

@ Дартениус: твой самый полезный!

QED 15.08.2012 03:23
убедитесь, что hashCode () ключевых объектов, которые вы помещаете в коллекцию, никогда не меняется, пока объект находится в коллекции This is exactly why overriding equals and hashcode together may not be necessary. Having hashCode pretty much precludes any changes to the object state while equals can tolerate fully mutable objects. You can safely put a mutable object into list as long as the equals contract remains intact but it's untrue for hashset/hashtables. Also if you wish a class to be able to server as key in hash structure it has to be designed as such (not just having hashCode)
bestsss 10.02.2013 18:34

@bestsss: Общее правило, которому следует следовать, заключается в том, что в любой момент времени, когда изменяемый аспект состояния объекта может измениться, объект должен иметь одного четко определенного владельца. Если объект переопределяет equals, чтобы зависеть от некоторого изменяемого состояния, любой словарь, в котором он был сохранен, будет «владеть» этим аспектом его состояния. Поскольку любой контекст выполнения, который пытается изменить это состояние, должен владеть им, это будет означать, что объект должен быть сначала удален из Словаря. В противном случае, если кто-то хочет изменить это правило, переопределите hashCode, чтобы он зависел только от неизменяемых свойств.

supercat 04.08.2013 20:48

@Darthenius или ярлык: ALTShiftS, а затем h.

mike 29.08.2013 12:55

@Darthenius Eclipse сгенерированный equals использует getClass (), что в некоторых случаях может вызвать проблемы (см. Эффективный элемент Java 8)

AndroidGecko 08.12.2013 22:46

Первая проверка на null не требуется, учитывая тот факт, что instanceof возвращает false, если его первый операнд равен нулю (снова эффективная Java).

izaban 13.12.2013 23:51

@AndroidGecko, может быть, это было раньше. Eclipse Kepler не генерировал код, содержащий getClass ().

Rui Marques 24.01.2014 17:09

Android Studio также может сгенерировать для вас equals () и hashCode ().

Brian 11.02.2014 00:01

Математический термин - «отношение эквивалентности», а не «отношение равенства».

Mike Housky 18.03.2014 08:52

equals используется для добавления / удаления элементов из коллекций, таких как CopyOnWriteArraySet, HashSet, если hashCode равен для двух разных объектов и т. д. equals должен быть симметричным, т.е. если B.equals (C) возвращает true, то C.equals (B) должен возвращать тот же результат. В противном случае ваше добавление / удаление этих XXXSet приведет к путанице. stackoverflow.com/questions/24920563/…

yalkris 29.07.2014 01:06

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

Amit Parashar 28.05.2015 12:34

при использовании instanceof вместо getClass () симметрия не всегда сохраняется

AbrahamDaniel 03.06.2015 06:31

Этот ответ - только половина дела. Здесь не упоминается ни одна из ловушек при переопределении метода equals в подклассе. На самом деле это заблуждение, поскольку простое добавление appendSuper в производный класс решит проблему. Это почти наверняка нарушит симметрию или транзитивность.

steinybot 29.06.2015 05:37

К сожалению, на самом деле никакой ответ не решает проблему, кроме, возможно, stackoverflow.com/a/55736/367796. Даже тогда я был бы более склонен пойти с комментарием @Blaisorblade, чтобы использовать подход canEqual stackoverflow.com/questions/27581/…

steinybot 29.06.2015 05:37

@ AnttiSykäri вы также можете добавить пример, например - когда мы хотим вставить определенный пользователем объект в SET, тогда нам нужно реализовать метод hashCode и equals, чтобы он добавлял только уникальный объект в SET

Manish Nagar 02.02.2016 09:30

В IntelliJ также есть мастер: щелкните правой кнопкой мыши имя класса> Создать .. (или ⌘N)> equals () и hashCode ().

philo 23.02.2016 07:11

почему instanceof вместо if ((obj == null) || (obj.getClass() != this.getClass()))? instanceof может создать проблему для родителя и ребенка.

Asif Mushtaq 25.03.2016 21:25

удивлены тем фактом, что enum не является частью ответа, не должны ли мы беспокоиться о таких полях?

Naman 13.10.2016 13:49

«Используйте тот же набор полей, который вы используете для вычисления equals () для вычисления hashCode ()» Меня учили, что хэш-код был «быстрым поиском», просто чтобы сузить объем того, что затем требует полной проверки «равно» . Поэтому в большинстве ситуаций я бы просто выбрал одно поле (например, «возраст» в этом примере), а не всегда включал все поля. Это плохая практика?

David Lavender 05.12.2017 19:32

Пояснение по поводу obj.getClass() != getClass().

Это утверждение является результатом недружественного наследования equals(). JLS (спецификация языка Java) указывает, что если A.equals(B) == true, то B.equals(A) также должен возвращать true. Если вы опустите этот оператор, наследование классов, которые переопределяют equals() (и изменяют его поведение), нарушит эту спецификацию.

Рассмотрим следующий пример того, что происходит, если оператор опущен:

    class A {
      int field1;

      A(int field1) {
        this.field1 = field1;
      }

      public boolean equals(Object other) {
        return (other != null && other instanceof A && ((A) other).field1 == field1);
      }
    }

    class B extends A {
        int field2;

        B(int field1, int field2) {
            super(field1);
            this.field2 = field2;
        }

        public boolean equals(Object other) {
            return (other != null && other instanceof B && ((B)other).field2 == field2 && super.equals(other));
        }
    }    

Делаем new A(1).equals(new A(1)) Также результат new B(1,1).equals(new B(1,1)) выдает верный, как и положено.

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

A a = new A(1);
B b = new B(1,1);
a.equals(b) == true;
b.equals(a) == false;

Очевидно, это неправильно.

Если вы хотите обеспечить симметричное состояние. a = b, если b = a и принцип подстановки Лискова вызывает super.equals(other) не только в случае экземпляра B, но и проверяет после экземпляра A:

if (other instanceof B )
   return (other != null && ((B)other).field2 == field2 && super.equals(other)); 
if (other instanceof A) return super.equals(other); 
   else return false;

Что выведет:

a.equals(b) == true;
b.equals(a) == true;

Если, если a не является ссылкой на B, тогда это может быть ссылка на класс A (потому что вы его расширяете), в этом случае вы вызываете super.equals()тоже.

Таким образом, вы можете сделать равные симметричными (при сравнении объекта суперкласса с объектом подкласса всегда используйте равные значения подкласса) if (obj.getClass ()! = This.getClass () && obj.getClass (). IsInstance (this) ) return obj.equals (this);

pihentagy 25.02.2010 13:40

@pihentagy - тогда я бы получил stackoverflow, когда класс реализации не переопределяет метод equals. не смешно.

Ran Biron 06.12.2010 22:16

Вы не получите stackoverflow. Если метод equals не переопределен, вы снова вызовете тот же код, но условие рекурсии всегда будет ложным!

Jacob Raihle 04.08.2013 16:32

@pihentagy: Как это ведет себя, если есть два разных производных класса? Если ThingWithOptionSetA может быть равен Thing при условии, что все дополнительные параметры имеют значения по умолчанию, а также для ThingWithOptionSetB, тогда должно быть возможно, чтобы ThingWithOptionSetA был равен ThingWithOptionSetB, только если все небазовые свойства обоих объектов соответствуют их значениям по умолчанию, но я не понимаю, как вы это проверяете.

supercat 28.12.2013 23:41

Проблема в том, что он нарушает транзитивность. Если добавить B b2 = new B(1,99), то b.equals(a) == true и a.equals(b2) == true, но b.equals(b2) == false.

nickgrim 25.06.2015 13:24

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

  1. Используйте оператор instanceof.
  2. Используйте this.getClass().equals(that.getClass()).

Я использую № 1 в реализации равенства final или при реализации интерфейса, который предписывает алгоритм для равенства (например, интерфейсы сбора java.util - правильный способ проверки с помощью (obj instanceof Set) или любого другого интерфейса, который вы реализуете). Обычно плохой выбор, когда можно переопределить равенство, потому что это нарушает свойство симметрии.

Вариант № 2 позволяет безопасно расширять класс без переопределения равенства или нарушения симметрии.

Если ваш класс также Comparable, методы equals и compareTo также должны быть согласованы. Вот шаблон для метода equals в классе Comparable:

final class MyClass implements Comparable<MyClass>
{

  …

  @Override
  public boolean equals(Object obj)
  {
    /* If compareTo and equals aren't final, we should check with getClass instead. */
    if (!(obj instanceof MyClass)) 
      return false;
    return compareTo((MyClass) obj) == 0;
  }

}

+1 за это. Ни getClass (), ни instanceof не являются панацеей, и это хорошее объяснение того, как подойти к обоим. Не думайте, что есть причина не делать this.getClass () == that.getClass () вместо использования equals ().

Paul Cantrell 25.04.2013 01:48

С этим есть одна проблема. Анонимные классы, которые не добавляют никаких аспектов и не переопределяют метод equals, не пройдут проверку getClass, даже если они должны быть равны.

steinybot 29.06.2015 05:27

@Steiny Мне непонятно, что объекты разных типов должны быть равны; Я думаю о различных реализациях интерфейса как об общем анонимном классе. Можете ли вы привести пример, подтверждающий вашу предпосылку?

erickson 30.06.2015 02:45

MyClass a = новый MyClass (123); MyClass b = new MyClass (123) {// Переопределить какой-либо метод}; // a.equals (b) ложно при использовании this.getClass (). equals (that.getClass ())

steinybot 07.07.2015 05:53

@Steiny Верно. Как и должно быть в большинстве случаев, особенно если метод переопределяется, а не добавляется. Рассмотрим мой пример выше. Если это не final, и метод compareTo() был переопределен для изменения порядка сортировки, экземпляры подкласса и суперкласса не должны считаться равными. Когда эти объекты использовались вместе в дереве, ключи, которые были «равны» согласно реализации instanceof, могли быть недоступны.

erickson 07.07.2015 18:41

Я обнаружил одну ловушку, когда два объекта содержат ссылки друг на друга (один из примеров - отношения родитель / потомок с помощью вспомогательного метода для родительского элемента для получения всех потомков). Подобные вещи довольно распространены, например, при отображении Hibernate.

Если вы включите оба конца отношения в свой хэш-код или тесты на равенство, можно попасть в рекурсивный цикл, который заканчивается исключением StackOverflowException. Самое простое решение - не включать коллекцию getChildren в методы.

Я думаю, что основная теория здесь состоит в том, чтобы различать атрибуты, агрегаты и ассоциаты объекта. ассоциации не должен участвовать в equals(). Если бы сумасшедший ученый создал мою копию, мы были бы эквивалентны. Но у нас не было бы одного отца.

Raedwald 29.09.2011 13:28

Для реализации, удобной для наследования, ознакомьтесь с решением Тала Коэна, Как правильно реализовать метод equals ()?

Резюме:

В своей книге Руководство по эффективному языку программирования Java (Addison-Wesley, 2001) Джошуа Блох утверждает, что «просто невозможно расширить экземпляр класса и добавить аспект при сохранении контракта равенства». Таль не согласен.

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

Пример:

class Point {
    private int x;
    private int y;
    protected boolean blindlyEquals(Object o) {
        if (!(o instanceof Point))
            return false;
        Point p = (Point)o;
        return (p.x == this.x && p.y == this.y);
    }
    public boolean equals(Object o) {
        return (this.blindlyEquals(o) && o.blindlyEquals(this));
    }
}

class ColorPoint extends Point {
    private Color c;
    protected boolean blindlyEquals(Object o) {
        if (!(o instanceof ColorPoint))
            return false;
        ColorPoint cp = (ColorPoint)o;
        return (super.blindlyEquals(cp) && 
        cp.color == this.color);
    }
}

Обратите внимание, что equals () должен работать в иерархиях наследования, если Принцип замены Лискова должно быть удовлетворено.

Взгляните на метод canEqual, описанный здесь - тот же принцип заставляет оба решения работать, но с canEqual вы не сравниваете одни и те же поля дважды (выше p.x == this.x будет проверяться в обоих направлениях): artima.com/lejava/articles/equality.html

Blaisorblade 14.12.2011 05:43

В любом случае, я не думаю, что это хорошая идея. Это делает контракт Equals излишне запутанным - тот, кто принимает два параметра Point, a и b, должен осознавать возможность того, что a.getX () == b.getX () и a.getY () == b.getY () может быть истинным, но a.equals (b) и b.equals (a) оба будут ложными (если только один из них является ColorPoint).

Kevin 12.08.2014 05:05

По сути, это похоже на if (this.getClass() != o.getClass()) return false, но гибко в том, что он возвращает false только в том случае, если производный класс (классы) потрудится изменить equals. Это правильно?

Aleksandr Dubinsky 19.02.2016 19:37

Есть некоторые проблемы, на которые стоит обратить внимание, если вы имеете дело с классами, которые сохраняются с помощью Object-Relationship Mapper (ORM), такого как Hibernate, если вы не думали, что это уже было неоправданно сложно!

Ленивые загруженные объекты - это подклассы

Если ваши объекты сохраняются с использованием ORM, во многих случаях вы будете иметь дело с динамическими прокси, чтобы избежать слишком ранней загрузки объекта из хранилища данных. Эти прокси реализованы как подклассы вашего собственного класса. Это означает, что this.getClass() == o.getClass() вернет false. Например:

Person saved = new Person("John Doe");
Long key = dao.save(saved);
dao.flush();
Person retrieved = dao.retrieve(key);
saved.getClass().equals(retrieved.getClass()); // Will return false if Person is loaded lazy

Если вы имеете дело с ORM, использование o instanceof Person - единственное, что будет вести себя правильно.

Ленивые загруженные объекты имеют нулевые поля

ORM обычно используют геттеры для принудительной загрузки ленивых загружаемых объектов. Это означает, что person.name будет null, если person загружается лениво, даже если person.getName() выполняет принудительную загрузку и возвращает «John Doe». По моему опыту, это чаще встречается в hashCode() и equals().

Если вы имеете дело с ORM, всегда используйте геттеры и никогда не используйте ссылки на поля в hashCode() и equals().

Сохранение объекта изменит его состояние

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

Я часто использую шаблон

if (this.getId() == null) {
    return this == other;
}
else {
    return this.getId().equals(other.getId());
}

Но: вы не можете включить getId() в hashCode(). Если вы это сделаете, при сохранении объекта его hashCode изменится. Если объект находится в HashSet, вы «никогда» его больше не найдете.

В моем примере с Person я, вероятно, использовал бы getName() для hashCode и getId() плюс getName() (просто для паранойи) для equals(). Это нормально, если есть некоторый риск «коллизий» для hashCode(), но никогда не подходит для equals().

hashCode() должен использовать неизменяемое подмножество свойств из equals().

@ Йоханнес Бродвалл: я не понимаю Saving an object will change it's state! hashCode должен возвращать int, так как вы будете использовать getName()? Можете привести пример для вашего hashCode

jimmybondy 01.11.2012 18:14

@jimmybondy: getName вернет объект String, который также имеет хэш-код, который можно использовать

mateusz.fiolka 02.03.2013 17:15

Для равных загляните в Секреты равных by Анжелика Лангер. Я люблю это очень сильно. Еще она отличный FAQ про Дженерики в Java. Просмотрите другие ее статьи здесь (прокрутите вниз до «Core Java»), где она также продолжает часть 2 и «сравнение смешанных типов». Получайте удовольствие от их чтения!

Все еще удивлен, что никто не рекомендовал для этого библиотеку guava.

 //Sample taken from a current working project of mine just to illustrate the idea

    @Override
    public int hashCode(){
        return Objects.hashCode(this.getDate(), this.datePattern);
    }

    @Override
    public boolean equals(Object obj){
        if ( ! obj instanceof DateAndPattern ) {
            return false;
        }
        return Objects.equal(((DateAndPattern)obj).getDate(), this.getDate())
                && Objects.equal(((DateAndPattern)obj).getDate(), this.getDatePattern());
    }

java.util.Objects.hash () и java.util.Objects.equals () являются частью Java 7 (выпущенной в 2011 году), поэтому вам не нужна Guava для этого.

herman 23.07.2013 17:33

конечно, но вам следует избегать этого, поскольку Oracle больше не предоставляет публичные обновления для Java 6 (так было с февраля 2013 года).

herman 25.07.2013 13:48

Ваш this в this.getDate() ничего не значит (кроме беспорядка)

Steve Kuo 29.04.2014 08:49

Для вашего выражения not instanceof нужна дополнительная скобка: if (!(otherObject instanceof DateAndPattern)) {. Согласен с Эрнаном и Стивом Куо (хотя это вопрос личных предпочтений), но тем не менее +1.

Amos M. Carpenter 11.12.2015 06:27

По логике имеем:

a.getClass().equals(b.getClass()) && a.equals(b)a.hashCode() == b.hashCode()

А вот нет наоборот!

Метод equals () используется для определения равенства двух объектов.

поскольку int значение 10 всегда равно 10. Но этот метод equals () касается равенства двух объектов. Когда мы говорим «объект», у него будут свойства. Эти свойства учитываются при принятии решения о равенстве. Необязательно, чтобы все свойства принимались во внимание для определения равенства, и это может быть принято в отношении определения класса и контекста. Затем можно переопределить метод equals ().

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

Данная реализация по умолчанию - это метод hashCode () в классе Object, который использует внутренний адрес объекта, преобразует его в целое число и возвращает его.

public class Tiger {
  private String color;
  private String stripePattern;
  private int height;

  @Override
  public boolean equals(Object object) {
    boolean result = false;
    if (object == null || object.getClass() != getClass()) {
      result = false;
    } else {
      Tiger tiger = (Tiger) object;
      if (this.color == tiger.getColor()
          && this.stripePattern == tiger.getStripePattern()) {
        result = true;
      }
    }
    return result;
  }

  // just omitted null checks
  @Override
  public int hashCode() {
    int hash = 3;
    hash = 7 * hash + this.color.hashCode();
    hash = 7 * hash + this.stripePattern.hashCode();
    return hash;
  }

  public static void main(String args[]) {
    Tiger bengalTiger1 = new Tiger("Yellow", "Dense", 3);
    Tiger bengalTiger2 = new Tiger("Yellow", "Dense", 2);
    Tiger siberianTiger = new Tiger("White", "Sparse", 4);
    System.out.println("bengalTiger1 and bengalTiger2: "
        + bengalTiger1.equals(bengalTiger2));
    System.out.println("bengalTiger1 and siberianTiger: "
        + bengalTiger1.equals(siberianTiger));

    System.out.println("bengalTiger1 hashCode: " + bengalTiger1.hashCode());
    System.out.println("bengalTiger2 hashCode: " + bengalTiger2.hashCode());
    System.out.println("siberianTiger hashCode: "
        + siberianTiger.hashCode());
  }

  public String getColor() {
    return color;
  }

  public String getStripePattern() {
    return stripePattern;
  }

  public Tiger(String color, String stripePattern, int height) {
    this.color = color;
    this.stripePattern = stripePattern;
    this.height = height;

  }
}

Пример вывода кода:

bengalTiger1 and bengalTiger2: true 
bengalTiger1 and siberianTiger: false 
bengalTiger1 hashCode: 1398212510 
bengalTiger2 hashCode: 1398212510 
siberianTiger hashCode: –1227465966

В суперклассе java.lang.Object есть два метода. Нам нужно переопределить их на настраиваемый объект.

public boolean equals(Object obj)
public int hashCode()

Равные объекты должны генерировать один и тот же хэш-код, пока они равны, однако неравные объекты не должны создавать разные хэш-коды.

public class Test
{
    private int num;
    private String data;
    public boolean equals(Object obj)
    {
        if (this == obj)
            return true;
        if ((obj == null) || (obj.getClass() != this.getClass()))
            return false;
        // object must be Test at this point
        Test test = (Test)obj;
        return num == test.num &&
        (data == test.data || (data != null && data.equals(test.data)));
    }

    public int hashCode()
    {
        int hash = 7;
        hash = 31 * hash + num;
        hash = 31 * hash + (null == data ? 0 : data.hashCode());
        return hash;
    }

    // other methods
}

Если вы хотите получить больше, проверьте эту ссылку как http://www.javaranch.com/journal/2002/10/equalhash.html

Это еще один пример, http://java67.blogspot.com/2013/04/example-of-overriding-equals-hashcode-compareTo-java-method.html

Радоваться, веселиться! @. @

Извините, но я не понимаю этого утверждения о методе hashCode: это незаконно, если он использует больше переменных, чем equals (). Но если я кодирую с большим количеством переменных, мой код компилируется. Почему это не законно?

Sam 14.11.2018 18:19

Другие вопросы по теме

Есть ли способ предотвратить переопределение метода в подклассах?
Как реализовать Enum с изменяемыми членами, сопоставимыми и хешируемыми по их индексу
Единый обработчик событий в коде C# для всех пользовательских кнопок/MAUI .NET8
Почему «новый» метод блокирует переопределение?
Почему я не могу получить доступ к общедоступному методу после переопределения защищенного метода?
Определение конкретной функциональности класса с использованием декораторов в качестве информации о переопределениях классов
Как переопределить реализацию функций протокола UnkeyedDecodingContainer по умолчанию?
Переопределить blpapi при получении данных Bloomberg (Python)
Невозможно переопределить изменяемое свойство свойством, доступным только для чтения, которое является переменной
Какие методы, унаследованные от класса Object, обычно следует переопределять?