Подтвердить что ты не робот

Почему я должен переопределять hashCode(), когда я переопределяю метод equals()?

Хорошо, я слышал из многих мест и источников, что всякий раз, когда я переопределяю метод 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() overriding является опцией, а скорее обязательной, как говорят все.

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

4b9b3361

Ответ 1

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

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

В соответствии с документацией для класса Object:

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

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

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

Ответ 2

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

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

Ответ 3

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

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

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

Ответ 4

Большинство других комментариев уже дали вам ответ: вам нужно сделать это, потому что есть коллекции (например, 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 со свойствами, которые могут быть изменены (изменчивыми), является действительно плохим идеей.

Ответ 5

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