Почему я должен переопределять hashCode (), когда переопределяю метод equals ()? - PullRequest
28 голосов
/ 25 апреля 2010

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

package test;

public class MyCustomObject {

    int intVal1;
    int intVal2;

    public MyCustomObject(int val1, int val2){
        intVal1 = val1;
        intVal2 = val2;
    }

    public boolean equals(Object obj){
        return (((MyCustomObject)obj).intVal1 == this.intVal1) && 
                (((MyCustomObject)obj).intVal2 == this.intVal2);
    }

    public static void main(String a[]){
        MyCustomObject m1 = new MyCustomObject(3,5);
        MyCustomObject m2 = new MyCustomObject(3,5);
        MyCustomObject m3 = new MyCustomObject(4,5);

        System.out.println(m1.equals(m2));
        System.out.println(m1.equals(m3));
    }
}

Здесь вывод true, false именно так, как я хочу, и я не забочусь о переопределении метода hashCode (). Это означает, что переопределение hashCode () является опцией, а не обязательной, как все говорят.

Я хочу второе подтверждение.

Ответы [ 5 ]

32 голосов
/ 25 апреля 2010

Это работает для вас, потому что ваш код не использует никаких функций (HashMap, HashTable), для которых требуется hashCode() API .

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

Согласно документации для класса объекта :

Общий контракт hashCode:

  • Всякий раз, когда он вызывается для одного и того же объекта более одного раза во время выполнения приложения Java, метод hashCode должен последовательно возвращать одно и то же целое число при условии, что никакая информация, используемая в сравнениях сравнения для объекта, не изменяется. Это целое число не должно оставаться согласованным при выполнении одного приложения другим исполнением того же приложения.

  • Если два объекта равны в соответствии с методом equals (Object), то вызов метода hashCode для каждого из двух объектов должен привести к одинаковому целочисленному результату .

11 голосов
/ 25 апреля 2010

Поскольку HashMap / Hashtable сначала будет искать объект с помощью hashCode ().

Если они не совпадают, hashmap будет утверждать, что объект не совпадает, и возвращение не существует на карте.

5 голосов
/ 25 апреля 2010

Причина, по которой вам нужно @Override ни то, ни другое, заключается в том, как они взаимодействуют с остальным API.

Вы обнаружите, что если вы поместите m1 в HashSet<MyCustomObject>, тогда это не contains(m2).Это несовместимое поведение и может вызвать много ошибок и хаоса.

Библиотека Java имеет множество функций.Чтобы заставить их работать для вас, вам нужно играть по правилам, и обеспечение согласованности equals и hashCode является одним из самых важных.

4 голосов
/ 06 декабря 2011

Большинство других комментариев уже дали вам ответ: вам нужно сделать это, потому что есть коллекции (то есть: HashSet, HashMap), которые используют hashCode в качестве оптимизации для «индексации» экземпляров объекта, и эти оптимизации ожидают, что если a.equals(b) ==> a.hashCode() == b.hashCode() (учтите, что обратное не выполняется).

Но в качестве дополнительной информации вы можете выполнить это упражнение:

class Box {
     private String value;
     /* some boring setters and getters for value */
     public int hashCode() { return value.hashCode(); }
     public boolean equals(Object obj) { 
           if (obj != null && getClass().equals(obj.getClass()) { 
               return ((Box) obj).value.equals(value); 
            } else { return false; }
     }
}

Сделайте это:

Set<Box> s = new HashSet<Box>();
Box b = new Box();
b.setValue("hello");
s.add(b);
s.contains(b); // TRUE
b.setValue("other");
s.contains(b); // FALSE
s.iterator().next() == b // TRUE!!! b is in s but contains(b) returns false

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

0 голосов
/ 18 марта 2017

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

...