Почему я должен переопределять hashCode (), когда я переопределяю метод equals ()?
Хорошо, я слышал из многих мест и источников, что всякий раз, когда я переопределяю метод equals (), мне нужно переопределить метод hashCode (). Но рассмотрим следующий fragment кода
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 является опцией, а скорее обязательной, как все говорят.
Я хочу получить второе подтверждение.
- Как проверить, равна ли моя строка нулевой?
- Есть ли полная ссылка на реализацию IEquatable?
- Какова лучшая страtagsя для Equals и GetHashCode?
- Почему мы не можем использовать '==' для сравнения двух чисел с плавающей запятой или двойных чисел
- Это плохая идея, если equals (null) вместо NullPointerException выбрасывает?
- BigDecimal равно () по сравнению с compareTo ()
- Разница между пустой и пустой ("") строкой Java
- Почему эти ==, но не `equals ()`?
- Как переопределить метод equals в java
- Есть ли утилита отражения Java для глубокого сравнения двух объектов?
- Как следует использовать равенства и hash-код при использовании JPA и Hibernate
- Метод Java - equals в базовом classе и в подclassах
- Понимание работы equals и hashCode в HashMap
Он работает для вас, потому что ваш код не использует никаких функций (HashMap, HashTable), которым нужен API hashCode()
.
Тем не менее, вы не знаете, будет ли ваш class (предположительно, не написанный как одноразовый) позже вызываться в коде, который действительно использует его объекты как hash-ключ, и в этом случае все будет затронуто.
Согласно документации для classа Object :
Общий контракт hashCode:
Всякий раз, когда он вызывается на одном и том же объекте более одного раза во время выполнения приложения Java, метод hashCode должен последовательно возвращать одно и то же целое число, если информация, используемая при равных сравнениях на объекте, не изменяется. Это целое число не должно оставаться согласованным с одним исполнением приложения на другое выполнение одного и того же приложения.
Если два объекта равны в соответствии с методом equals (Object), то вызов метода hashCode для каждого из двух объектов должен давать одинаковый целочисленный результат .
Поскольку HashMap / Hashtable будет искать объект с помощью hashCode ().
Если они не совпадают, hashmap будет утверждать, что объект не совпадает и возврат не существует на карте.
Причина, по которой вам нужно @Override
ни или и другое, связано с тем, как они взаимосвязаны с остальной частью API.
Вы обнаружите, что если вы поместите m1
в HashSet
, то он не contains(m2)
. Это противоречивое поведение и может вызвать множество ошибок и хаоса.
Библиотека Java имеет множество функциональных возможностей. Чтобы заставить их работать на вас, вам нужно играть по правилам, и убедиться, что equals
и hashCode
являются совместимыми, является одним из самых важных.
Большинство других комментариев уже дали вам ответ: вам нужно сделать это, потому что есть коллекции (например, HashSet, HashMap), который использует hashCode как оптимизацию для «индексации» экземпляров объекта, эти оптимизации предполагают, что если: a.equals(b)
==> a.hashCode() == b.hashCode()
( 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 s = new HashSet (); 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
со свойствами, которые могут быть изменены (изменчивыми), является действительно плохой идеей.
Это в первую очередь важно при поиске объекта с использованием его значения hashCode () в коллекции (например, HashMap, HashSet и т. Д.). Каждый объект возвращает другое значение hashCode (), поэтому вы должны переопределить этот метод, чтобы последовательно генерировать значение hashCode на основе состояния объекта, чтобы помочь алгоритму Collections найти значения в хеш-таблице.