Когда переопределить метод hashcode [duplicate]

Подумайте об анонимном объекте, поскольку он сам имеет имя:

a = {}; // The variable "a" now points to (holds) an anonymous object.
b = a; // "b" points to the same anonymous object held by "a".
a = 123; // "a" now holds some other value.
b; // "b" still holds the anonymous object.

Ключ должен помнить, что переменные содержат ссылки на objects , а не ссылки на другие переменные. И тот же объект может ссылаться на любое количество переменных.

275
задан Exploring 21 March 2018 в 04:16
поделиться

25 ответов

Джошуа Блох говорит об эффективном Java

Вы должны переопределить hashCode () в каждом классе, который переопределяет equals (). Несоблюдение этого требования приведет к нарушению общего договора для Object.hashCode (), что предотвратит правильное функционирование вашего класса в сочетании со всеми коллекциями на основе хешей, включая HashMap, HashSet и Hashtable.

< / blockquote>

Попробуем понять это с примером того, что произойдет, если мы переопределим equals() без переопределения hashCode() и попытаемся использовать Map.

Скажем, у нас есть класс как и это, и что два объекта из MyClass равны, если их importantField равны (с hashCode() и equals(), сгенерированными затмением)

public class MyClass {

    private final String importantField;
    private final String anotherField;

    public MyClass(final String equalField, final String anotherField) {
        this.importantField = equalField;
        this.anotherField = anotherField;
    }

    public String getEqualField() {
        return importantField;
    }

    public String getAnotherField() {
        return anotherField;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result
                + ((importantField == null) ? 0 : importantField.hashCode());
        return result;
    }

    @Override
    public boolean equals(final Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        final MyClass other = (MyClass) obj;
        if (importantField == null) {
            if (other.importantField != null)
                return false;
        } else if (!importantField.equals(other.importantField))
            return false;
        return true;
    }

}

Только переопределение equals

Если превышено только equals, тогда, когда вы вызываете myMap.put(first,someValue), сначала будет хеш к некоторому ведру, и когда вы вызываете myMap.put(second,someOtherValue), он будет хешировать в каком-то другом ковше (поскольку у них есть другой hashCode ]). Таким образом, хотя они равны, поскольку они не имеют хеша в одном и том же ковше, карта не может ее реализовать, и оба они остаются на карте.


Хотя нет необходимости переопределить equals(), если мы переопределим hashCode(), посмотрим, что произойдет в этом конкретном случае, когда мы знаем, что два объекта из MyClass равны, если их importantField равны, но мы не переопределяем equals().

Только переопределение hashCode

Представьте, что у вас есть

MyClass first = new MyClass("a","first");
MyClass second = new MyClass("a","second");

Если вы только переопределяете hashCode, тогда, когда вы вызываете myMap.put(first,someValue), это занимает сначала, вычисляет его hashCode и сохраняет его в данном ковше. Затем, когда вы вызываете myMap.put(second,someOtherValue), он должен заменить сначала вторым в соответствии с Documentation Document , потому что они равны (в соответствии с бизнес-требованием).

Но проблема в том, что равен не было переопределено, поэтому, когда хэши карты second и повторяются через ведро, глядя, есть ли объект k, такой, что second.equals(k) истинно, он не будет найден, поскольку second.equals(first) будет false.

Надеюсь, что было ясно

416
ответ дан Lombo 17 August 2018 в 11:12
поделиться
  • 1
    не могли бы вы рассказать немного больше, во втором случае, почему второй объект должен идти в другом ковше? – Hussain Akhtar Wahid 'Ghouri' 6 May 2014 в 00:31
  • 2
    Мне не нравится этот ответ, потому что он предполагает, что вы не можете переопределить hashCode () без переопределения equals (), что просто неверно. Вы говорите, что ваш примерный код (часть «переопределить только hashCode») не будет работать, потому что вы определяете ваши два объекта как равные, но, к сожалению, это определение находится только в вашей голове. В первом примере у вас есть два не равных объекта с одним и тем же хэш-кодом, и это совершенно законно. Поэтому причина, по которой вам нужно переопределить equals (), заключается не в том, что вы уже переопределили hashCode (), а потому, что хотите переместить ваши «равны», определение от вашей головы до кода. – user2543253 30 December 2014 в 16:38
  • 3
    if you think you need to override one, then you need to override both of them неверно. Вы должны переопределить hashCode, если ваш класс переопределяет equals, но обратное неверно. – i_am_zero 17 October 2015 в 09:00
  • 4
    Я думаю, что полностью ok переопределить только hashCode () без переопределения equals (). Это также написано в Эффективной Java : books.google.fr/… – Stas 4 April 2016 в 12:59
  • 5
    @PhantomReference, обратите внимание, что только переопределение equals нарушит контракт, указанный в javadoc файла Object: "Если два объекта равны в соответствии с методом equals(Object), то вызов метода hashCode на каждый из двух объектов должен давать одинаковый целочисленный результат. & quot; Конечно, не все части всех контрактов выполняются во всем коде, но, тем не менее, формально говоря, это нарушение, и я считаю это ошибкой ожидая. – aioobe 27 November 2016 в 11:20
Метод

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

Метод объектов hashCode() используется, когда мы вставляем их в HashTable, HashMap или HashSet. Подробнее о HashTables на Wikipedia.org для справки.

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

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

Итак, как мы видим, комбинация методов hashCode() и equals() используется при хранении и при поиске объектов в HashTable.

ПРИМЕЧАНИЯ:

  1. Всегда используйте одни и те же атрибуты объекта для генерации hashCode() и equals() обоих. Как и в нашем случае, мы использовали идентификатор сотрудника.
  2. equals() должен быть последовательным (если объекты не изменены, то он должен продолжать возвращать одно и то же значение).
  3. a.equals(b), тогда a.hashCode() должен быть таким же, как b.hashCode().
  4. Если вы переопределите один, тогда вы должны переопределить другой.

http : //parameshk.blogspot.in/2014/10/examples-of-comparable-comporator.html

11
ответ дан Aakash Goplani 17 August 2018 в 11:12
поделиться
  • 1
    Интересно, что переопределяет только hashCode () . Все в порядке, правда? Или могут быть и проблематичные случаи? – Stas 4 April 2016 в 13:44
  • 2
    hashCode() не используется для возврата уникального целого для каждого объекта. Это невозможно. Вы противоречили этому во втором предложении четвертого абзаца. – user207421 17 June 2017 в 01:07
  • 3
    Это вводящий в заблуждение и неправильный ответ. Overriding (= only =) hashCode () гарантирует, что каждый объект, который создается экземпляром соответствующего класса со схожими свойствами, имеет одинаковый хеш-код. Но это не будет полезно, поскольку ни один из них не будет равен друг другу. – Muhammad Faisal Hyder 23 June 2017 в 20:51
  • 4
    @EJP, большая часть времени hascode () вернет уникальный интергер для двух разных объектов. Но есть вероятность столкнуться с hascode для двух разных объектов, эта концепция называется Hashcode Collision . Пожалуйста, обратитесь: tech.queryhome.com/96931/… – Paramesh Korrakuti 18 September 2017 в 10:14

Методы equals и hashcode определены в классе объектов. По умолчанию, если метод equals возвращает true, система будет идти дальше и проверять значение хэш-кода. Если хэш-код из двух объектов также одинаковый, тогда объекты будут считаться одинаковыми. Поэтому, если вы переопределяете только метод equals, то, хотя метод overridden equals указывает, что 2 объекта равны, системный хэш-код может не указывать на то, что 2 объекта равны. Поэтому нам нужно переопределить хэш-код.

3
ответ дан Aarti 17 August 2018 в 11:12
поделиться
  • 1
    Если метод equals возвращает true, нет необходимости проверять хэш-код. Однако, если два объекта имеют разные хэш-коды, они должны иметь возможность рассматривать их как разные, не называя равных. Кроме того, знание о том, что ни одна из вещей в списке не имеет определенного хеш-кода, подразумевает, что ни одна из вещей в списке не может сопоставить этот объект с этим хэш-кодом. В качестве простого примера, если у вас есть список объектов, чьи хэш-коды являются четными числами, а список объектов, где они являются нечетными числами, ни один объект, чей хэш-код является четным числом, будет во втором списке. – supercat 28 July 2013 в 20:13
  • 2
    Если бы у одного были два объекта X и Y, чья "равна" методы указывали, что они совпадали, но хэш-код X был четным числом, а хэш-код Y был нечетным числом, сборник, как описано выше, который отметил, что хэш-код объекта Y был нечетным и сохранил его во втором списке, не смог бы найти соответствие для объекта X. Было бы замечательно, что хэш-код X был четным, и поскольку во втором списке нет объектов с четными хэш-кодами, он не стал бы искать там что-то, что соответствует X, хотя Y будет соответствовать X. Что вы должны сказать ... – supercat 28 July 2013 в 20:17
  • 3
    ... было бы то, что многие коллекции избегают сравнивать вещи, чьи хэш-коды означают, что они не могут быть равными. Учитывая два объекта, чьи хэш-коды неизвестны, часто быстрее сравнивать их напрямую, чем вычислять их хэш-коды, поэтому нет никакой гарантии, что вещи, которые сообщают о неравных хеш-кодах, но возвращают true для equals, не будут считаться совпадающими. С другой стороны, если коллекции случаются, замечают, что вещи не могут иметь один и тот же хэш-код, они, вероятно, не заметят, что они равны. – supercat 28 July 2013 в 20:20

Методы Equals и Hashcode в Java

Это методы класса java.lang.Object, который является суперклассом всех классов (пользовательских классов и других, определенных в java API).

Реализация:

public boolean equals (Object obj)

public int hashCode ()

public boolean equals (Object obj)

Этот метод просто проверяет, ссылаются ли на два объекта ссылки x и y на один и тот же объект. т.е. он проверяет, если х == у

Это рефлексивно:.. для любого опорного значения х, x.equals (х) должна возвращать верно

Он симметричен: для любых ссылочных значений x и y, x.equals (y) должен возвращать true тогда и только тогда, когда y.equals (x) возвращает true.

Это транзитивно: для любых ссылочных значений x, y и z, если x.equals (y) возвращает true, а y.equals (z) возвращает true, тогда x.equals (z) должно возвращать true.

Согласовано: для любых ссылочных значений x и y, множественные вызовы x.equals (y) последовательно возвращают true или последовательно возвращают false, если никакая информация не используется при равных сравнениях на объект изменяется.

Для любого ненулевого опорного значения х, x.equals (NULL) должен возвращать FALSE.

общественных Int хэш-код ( )

Этот метод возвращает значение хеш-кода для объекта, на который вызывается этот метод. Этот метод возвращает значение хеш-кода как целое число и поддерживается для использования классов сбора на основе хэширования, таких как Hashtable, HashMap, HashSet и т. Д. Этот метод должен быть переопределен в каждом классе, который переопределяет метод equals.

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

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

Это целое число не должно оставаться согласованным с одним исполнением приложения на другое выполнение того же приложения.

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

Не требуется, чтобы, если два объекта неравны в соответствии с методом equals (java.lang.Object), то вызов hashCode метод на каждом из двух объектов должен производить различные целочисленные результаты. Тем не менее, программист должен знать, что создание отдельных целочисленных результатов для неравных объектов может улучшить производительность хэш-таблиц.

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

Ресурсы:

JavaRanch

Изображение

5
ответ дан Aftab Virtual 17 August 2018 в 11:12
поделиться

Bah - «Вы должны переопределить hashCode () в каждом классе, который переопределяет equals ().»

[из Effective Java, by Joshua Bloch?]

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

Конечно, они должны были назначить интерфейс на объекты, написанные для использования в качестве ключей? Несмотря на это, Object никогда не должен был предоставлять hashCode () и equals () imho. Вероятно, это поощряло множество сломанных хеш-коллекций.

Но, во всяком случае, я думаю, что «правило» написано обратно. Тем временем я буду избегать использования «равных» для методов тестирования равенства: - (

-4
ответ дан Alan Dobbie 17 August 2018 в 11:12
поделиться

Причина этого: когда ваши поля объектов могут быть пустыми, реализация Object.equals может быть болью, потому что вам нужно отдельно проверить значение null. Использование Objects.equal позволяет выполнять проверки равных с помощью NULL-чувствительности, не рискуя исключением NullPointerException. Objects.equal("a", "a"); // returns true Objects.equal(null, "a"); // returns false Objects.equal("a", null); // returns false Objects.equal(null, null); // returns true

1
ответ дан aman 17 August 2018 в 11:12
поделиться
  • 1
    Никоим образом не отвечает на вопрос. – user207421 16 June 2017 в 23:53

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

Person p1 = new Person("A",23);
Person p2 = new Person("A",23);
HashMap map = new HashMap();
map.put(p1,"value 1");
map.put(p2,"value 2");

Здесь p1 & amp; p2 будет считать, что только один объект и map размер будут только 1, потому что они равны.

0
ответ дан Ambrish Rajput 17 August 2018 в 11:12
поделиться

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

Это приводит к проблеме, когда вы используете коллекцию Map, а ключ имеет тип Persistent, тип StringBuffer / builder. Поскольку они не переопределяют equals () и hashCode () в отличие от класса String, equals () возвращает false, когда вы сравниваете два разных объекта, хотя оба имеют одинаковое содержимое. Он заставит hashMap хранить одинаковые ключи содержимого. Сохранение одинаковых ключей содержимого означает, что оно нарушает правило Карты, поскольку Map не позволяет дублировать ключи вообще. Поэтому вы переопределяете методы equals (), а также методы hashCode () в своем классе и предоставляете реализацию (IDE может генерировать эти методы), чтобы они работали так же, как equals () и hashCode () и не допускали одинаковые ключи содержимого.

Вы должны переопределить метод hashCode () вместе с equals (), потому что equals () работает по hashcode.

Кроме того, переопределение метода hashCode () вместе с equals () помогает унаследовать контракт equals () - hashCode (): «Если два объекта равны, то они должны иметь одинаковый хеш-код».

Когда вам нужно написать специальную реализацию для hashCode ()?

Как мы знаем, внутренняя работа HashMap основана на принципе Hashing. Существуют определенные ведра, в которых хранятся записи. Вы настраиваете реализацию hashCode () согласно вашему требованию, чтобы объекты той же категории могли храниться в одном индексе. при сохранении значений в коллекции карт с использованием метода put(k,v), внутренняя реализация put ():

put(k, v){
hash(k);
index=hash & (n-1);
}

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

Вот и все!

2
ответ дан Arun Raaj 17 August 2018 в 11:12
поделиться

Рассмотрим коллекцию шаров в ведре, все в черном цвете. Ваша задача - покрасить эти шары следующим образом и использовать их для соответствующей игры,

Для тенниса - желтый, красный. Для крикета - белый

Теперь ведро имеет шары в трех цветах: желтый, красный и белый. И теперь вы сделали раскраску. Только вы знаете, какой цвет для какой игры.

Раскрашивание шаров - Хеширование. Выбор мяча для игры - Равно.

Если вы сделали раскраску, а кто-то выбрал мяч для крикета или тенниса, они не будут игнорировать цвет !!!

5
ответ дан bharanitharan 17 August 2018 в 11:12
поделиться

Хорошо, позвольте мне объяснить концепцию очень простыми словами.

Во-первых, с более широкой точки зрения у нас есть коллекции, а hashmap является одной из данных в коллекциях.

To понять, почему мы должны переопределять оба метода equals и hashcode, если вам нужно сначала понять, что такое hashmap и что делает.

Хеш-карта - это структура данных, в которой хранятся пары значений ключа в массиве. Давайте скажем [], где каждый элемент в 'a' является парой значений ключа.

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

Теперь почему используется хэшмап? Если нам нужно искать среди большого массива, то поиск по каждому из них, если они не будут эффективными, так что хэш-метод говорит нам, что позволяет предварительно обрабатывать массив с некоторой логикой и группировать элементы на основе этой логики, т. Е. Hashing

, например: у нас есть массив 1,2,3,4,5,6,7,8,9,10,11, и мы применяем хеш-функцию mod 10, поэтому 1,11 будут сгруппированы вместе. Поэтому, если бы нам пришлось искать 11 в предыдущем массиве, нам пришлось бы перебирать полный массив, но когда мы группируем его, мы ограничиваем объем итераций, тем самым улучшая скорость. Эта структура данных, используемая для хранения всей вышеприведенной информации, может рассматриваться как 2d-массив для простоты

. Теперь помимо вышеизложенного hashmap также говорит, что он не добавит в него никаких дубликатов. И это главная причина, по которой мы должны переопределить значения equals и hashcode

. Поэтому, когда в его объяснении объясняется внутренняя работа hashmap, нам нужно найти, какие методы имеет hashmap, и как это следует за приведенным выше правила, которые я объяснил выше

, поэтому в hashmap есть метод, называемый put (K, V), и в соответствии с hashmap он должен следовать приведенным выше правилам эффективного распределения массива и не добавлять никаких дубликатов

, так что put put is состоит в том, что он сначала сгенерирует хэш-код для данного ключа, чтобы решить, какой индекс должен иметь значение. Если в этом индексе ничего не присутствует, тогда добавляется новое значение, если что-то уже присутствует там, тогда новое значение должно быть добавлено после окончания связанного списка по этому индексу. но не помните, что дубликаты не должны добавляться в соответствии с желаемым поведением хэш-карты. поэтому давайте предположим, что у вас есть два объекта Integer aa = 11, bb = 11. как каждый объект, полученный из класса объекта, реализация по умолчанию для сравнения двух объектов заключается в том, что она сравнивает ссылку, а не значения внутри объекта. Таким образом, в приведенном выше случае оба семантически равных будут терпеть неудачу в тесте равенства и возможность того, что будут существовать два объекта, один и тот же хэш-код и одинаковые значения, что создает дубликаты. Если мы переопределим, мы могли бы избежать добавления дубликатов. Вы также можете обратиться к Подробности работы

import java.util.HashMap;


public class Employee {

String name;
String mobile;
public Employee(String name,String mobile) {
    this.name=name;
    this.mobile=mobile;
}

@Override
public int hashCode() {
    System.out.println("calling hascode method of Employee");
    String str=this.name;
    Integer sum=0;
    for(int i=0;i<str.length();i++){
        sum=sum+str.charAt(i);
    }
    return sum;

}
@Override
public boolean equals(Object obj) {
    // TODO Auto-generated method stub
    System.out.println("calling equals method of Employee");
    Employee emp=(Employee)obj;
    if(this.mobile.equalsIgnoreCase(emp.mobile)){

        System.out.println("returning true");
        return true;
    }else{
        System.out.println("returning false");
        return false;
    }


}

public static void main(String[] args) {
    // TODO Auto-generated method stub

    Employee emp=new Employee("abc", "hhh");
    Employee emp2=new Employee("abc", "hhh");
    HashMap<Employee, Employee> h=new HashMap<>();
    //for (int i=0;i<5;i++){
        h.put(emp, emp);
        h.put(emp2, emp2);

    //}

    System.out.println("----------------");
    System.out.println("size of hashmap: "+h.size());


}

}
11
ответ дан Chetan 17 August 2018 в 11:12
поделиться
  • 1
    У меня есть одна путаница, почему нам нужно переопределить метод equals, когда мы переопределяем метод hashCode в случае HashMap? В любом случае hashmap заменяет значение, если hashcode объекта равен. – Vikas Verma 13 March 2017 в 09:44
  • 2
    @WikasVerma hashmap не заменяет никакого значения, если хэш-код объектов равен, он решает только индекс, где должен быть добавлен новый добавленный объект к хэш-карте. Теперь в индексе могут быть объекты, поэтому, чтобы избежать дублирования, мы переопределяем метод equals, и мы пишем логику для определения, когда два объекта в сравнении должны рассматриваться как равные. Если не переопределить, то объекты, имеющие одинаковые значения, будут сохранены, поскольку ссылка обоих объектов будет различной – Chetan 29 March 2018 в 20:36

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

Учитывая выше, значение по умолчанию равно () в Object is ==, который делает сравнение по адресу, hashCode () возвращает адрес в целочисленном (хеш по фактическому адресу), который снова отличается для отдельного объекта.

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

1
ответ дан Cleonjoys 17 August 2018 в 11:12
поделиться

В приведенном ниже примере, если вы закомментируете переопределение для equals или hashcode в классе Person, этот код не сможет найти Tom's order. Использование реализации hashcode по умолчанию может приводить к сбоям в поисках хеш-таблицы.

То, что я имею ниже, - это упрощенный код, который подтягивает порядок людей от Person. Человек используется в качестве ключа в хэш-таблице.

public class Person {
    String name;
    int age;
    String socialSecurityNumber;

    public Person(String name, int age, String socialSecurityNumber) {
        this.name = name;
        this.age = age;
        this.socialSecurityNumber = socialSecurityNumber;
    }

    @Override
    public boolean equals(Object p) {
        //Person is same if social security number is same

        if ((p instanceof Person) && this.socialSecurityNumber.equals(((Person) p).socialSecurityNumber)) {
            return true;
        } else {
            return false;
        }

    }

    @Override
    public int hashCode() {        //I am using a hashing function in String.java instead of writing my own.
        return socialSecurityNumber.hashCode();
    }
}


public class Order {
    String[]  items;

    public void insertOrder(String[]  items)
    {
        this.items=items;
    }

}



import java.util.Hashtable;

public class Main {

    public static void main(String[] args) {

       Person p1=new Person("Tom",32,"548-56-4412");
        Person p2=new Person("Jerry",60,"456-74-4125");
        Person p3=new Person("Sherry",38,"418-55-1235");

        Order order1=new Order();
        order1.insertOrder(new String[]{"mouse","car charger"});

        Order order2=new Order();
        order2.insertOrder(new String[]{"Multi vitamin"});

        Order order3=new Order();
        order3.insertOrder(new String[]{"handbag", "iPod"});

        Hashtable<Person,Order> hashtable=new Hashtable<Person,Order>();
        hashtable.put(p1,order1);
        hashtable.put(p2,order2);
        hashtable.put(p3,order3);

       //The line below will fail if Person class does not override hashCode()
       Order tomOrder= hashtable.get(new Person("Tom", 32, "548-56-4412"));
        for(String item:tomOrder.items)
        {
            System.out.println(item);
        }
    }
}
2
ответ дан developer747 17 August 2018 в 11:12
поделиться

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

2
ответ дан Dewfy 17 August 2018 в 11:12
поделиться

Согласно документации Java, разработчики должны переопределять оба метода для достижения полностью работающего механизма равенства, и недостаточно просто реализовать метод equals () .

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

Переопределение equals () будет служить вашим потребностям при проверке равенства двух нормальных объектов, а также будет работать с вами при поиске элемента внутри списка .

Однако при работе с структурами хэширования вы будете работать: HashSet, HashMap, HashTable ..

В этом учебном пособии подробно описаны примеры, почему необходимо всегда переопределять equals () и hashcode () вместе. Это стоит прочитать, проверьте это.

2
ответ дан Hussein Terek 17 August 2018 в 11:12
поделиться

Это полезно при использовании Объектов значения . Ниже приведен фрагмент из Portland Pattern Repository :

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

Таким образом, я могу иметь несколько копий объекта, который представляет дату 16 января 1998 года. Любая из этих копий будет равна друг другу. Для небольшого объекта, такого как это, часто легче создавать новые и перемещать их, а не полагаться на один объект для представления даты.

Объект значения должен всегда переопределять .equals () в Java (или = в Smalltalk). (Не забудьте также переопределить .hashCode ().)

3
ответ дан Ionuț G. Stan 17 August 2018 в 11:12
поделиться

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

Учитывая, что для значений экземпляра и значений hascode обычно требуется знание того, что составляет объект, они, как правило, должны быть переопределены в вашем классе иметь какой-либо ощутимый смысл.

5
ответ дан PaulJWilliams 17 August 2018 в 11:12
поделиться

Чтобы использовать наши собственные объекты класса как ключи в таких коллекциях, как HashMap, Hashtable и т. д., мы должны переопределить оба метода (hashCode () и equals ()), узнав о внутренней работе коллекции. В противном случае это приводит к неправильным результатам, которых мы не ожидаем.

6
ответ дан Prashanth - codeforeach.com 17 August 2018 в 11:12
поделиться

Идентичность - это не равенство.

  • равно оператору == тестового тождества.
  • equals(Object obj) метод сравнивает тест равенства (т.е. нам нужно сказать равенство, переопределяя метод)

Почему мне нужно переопределить методы equals и hashCode в Java?

Сначала мы должны понять использование метода equals.

Для того, чтобы идентифицировать различия между двумя объектами, нам нужно переопределить метод equals.

Например:

Customer customer1=new Customer("peter");
Customer customer2=customer1;
customer1.equals(customer2); // returns true by JVM. i.e. both are refering same Object
------------------------------
Customer customer1=new Customer("peter");
Customer customer2=new Customer("peter");
customer1.equals(customer2); //return false by JVM i.e. we have two different peter customers.

------------------------------
Now I have overriden Customer class equals method as follows:
 @Override
    public boolean equals(Object obj) {
        if (this == obj)   // it checks references
            return true;
        if (obj == null) // checks null
            return false;
        if (getClass() != obj.getClass()) // both object are instances of same class or not
            return false;
        Customer other = (Customer) obj;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name)) // it again using bulit in String object equals to identify the difference 
            return false;
        return true; 
    }
Customer customer1=new Customer("peter");
Customer customer2=new Customer("peter");
Insteady identify the Object equality by JVM, we can do it by overring equals method.
customer1.equals(customer2);  // returns true by our own logic

Теперь метод hashCode может легко понять.

hashCode создает целое число для хранения объекта в структурах данных, таких как HashMap, HashSet.

Предположим, что мы переопределим метод равенства Customer, как указано выше,

customer1.equals(customer2);  // returns true by our own logic

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

  • экземпляры un-equal могут иметь один и тот же хэш-код.
  • равные экземпляры должны возвращать одинаковый хэш-код.
13
ответ дан Premraj 17 August 2018 в 11:12
поделиться
  • 1
    Это то, что я искал с последних 1 часа. Удивительный помощник (y) – Adnan 31 July 2017 в 06:35

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

  1. Найти правое ведро (используя hashCode ())
  2. Искать ведро для правого элемента (используя equals ())

Вот небольшой пример, почему мы должны переопределять equals () и hashcode (). Рассмотрим класс Employee, который имеет два возраста и имя поля.

public class Employee {

    String name;
    int age;

    public Employee(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == this)
            return true;
        if (!(obj instanceof Employee))
            return false;
        Employee employee = (Employee) obj;
        return employee.getAge() == this.getAge()
                && employee.getName() == this.getName();
    }

    // commented    
    /*  @Override
        public int hashCode() {
            int result=17;
            result=31*result+age;
            result=31*result+(name!=null ? name.hashCode():0);
            return result;
        }
     */
}

Теперь создайте класс, вставьте объект Employee в HashSet и проверьте, присутствует ли этот объект.

public class ClientTest {
    public static void main(String[] args) {
        Employee employee = new Employee("rajeev", 24);
        Employee employee1 = new Employee("rajeev", 25);
        Employee employee2 = new Employee("rajeev", 24);

        HashSet<Employee> employees = new HashSet<Employee>();
        employees.add(employee);
        System.out.println(employees.contains(employee2));
        System.out.println("employee.hashCode():  " + employee.hashCode()
        + "  employee2.hashCode():" + employee2.hashCode());
    }
}

Он будет печатать

false
employee.hashCode():  321755204  employee2.hashCode():375890482

Теперь раскомментируйте метод hashcode () выполните то же самое, и выход будет

true
employee.hashCode():  -938387308  employee2.hashCode():-938387308

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

132
ответ дан rajeev pani.. 17 August 2018 в 11:12
поделиться
  • 1
    Лучший пример ... – Steer360 26 January 2017 в 20:48
  • 2
    Прекрасный пример. Ясно продемонстрировал разницу! – Chip 6 May 2017 в 16:22
  • 3
    Лучший пример ... – Sritam Jagadev 29 June 2017 в 19:47
  • 4
    приятно объяснил @rajeev – VedX 12 September 2017 в 08:50
  • 5
    @VikasVerma равный объект будет иметь равный хэш-код, не означает, что неравный объект будет иметь неравный хэш-код. Что делать, если объекты на самом деле разные, но их хэш-код одинаковый? – Ravi 12 December 2017 в 07:21

Java ставит правило, что

"Если два объекта равны с использованием метода equals класса Object, то метод hashcode должен давать одинаковое значение для этих двух объектов."

< / blockquote>

Итак, если в нашем классе мы переопределяем equals, мы должны переопределить метод hashcode также для подбора этого правила. Эти оба метода equals и hashcode используются в Hashtable для хранения значений как пары ключ-значение. Если мы переопределяем один, а не другой, существует вероятность того, что хеш-таблица может работать не так, как мы хотим, если мы используем такой объект как ключ.

5
ответ дан Ritesh Kaushik 17 August 2018 в 11:12
поделиться

Оба метода определены в классе Object. И оба они в своей простейшей реализации. Поэтому, когда вам нужно, вы хотите добавить еще несколько реализаций к этим методам, тогда вы переопределяете свой класс.

Для метода Ex: equals () в объекте проверяется его равенство по ссылке. Поэтому, если вам нужно сравнить его состояние, тогда вы можете переопределить это, как это сделано в классе String.

17
ответ дан Shashi 17 August 2018 в 11:12
поделиться

Вы должны переопределить hashCode () в каждом классе, который переопределяет equals (). Несоблюдение этого требования приведет к нарушению общего договора для Object.hashCode (), что предотвратит правильное функционирование вашего класса в сочетании со всеми коллекциями на основе хешей, включая HashMap, HashSet и Hashtable.

& nbsp; & nbsp; из Эффективная Java , Джошуа Блох

Последовательно определяя equals() и hashCode(), вы можете улучшить удобство использования ваших классов в качестве ключей в хеше основанные на коллекции. Поскольку API-документ для hashCode объясняет: «Этот метод поддерживается в интересах хеш-таблиц, таких как функции, предоставленные java.util.Hashtable».

Лучший ответ на ваш вопрос о том, как эффективно реализовать эти методы, предлагает вам прочитать главу 3 из Эффективной Java .

48
ответ дан Soumitri Pattnaik 17 August 2018 в 11:12
поделиться
  • 1
    Это правильный ответ. Разумеется, к тому, что, если вы никогда не используете класс в хэш-коллекции, то не имеет значения, что вы не реализовали hashCode(). – slim 15 October 2015 в 15:36
  • 2
    В более сложных случаях вы никогда не знаете, используют ли используемые вами коллекции хеши, поэтому держитесь подальше от & quot; не имеет значения, что вы не реализовали hashCode () & quot; – Victor Sergienko 19 March 2016 в 21:47
  • 3
    Могу ли я переопределить hashCode () без переопределения equals ()? – Stas 4 April 2016 в 13:45
  • 4
    @StasS, да, вопреки тому, что говорит принятый ответ. См. Объяснение во второй части этой статьи: Почему вы должны всегда переопределять hashCode при переопределении equals – aioobe 28 November 2016 в 08:50
public class Employee {

    private int empId;
    private String empName;

    public Employee(int empId, String empName) {
        super();
        this.empId = empId;
        this.empName = empName;
    }

    public int getEmpId() {
        return empId;
    }

    public void setEmpId(int empId) {
        this.empId = empId;
    }

    public String getEmpName() {
        return empName;
    }

    public void setEmpName(String empName) {
        this.empName = empName;
    }

    @Override
    public String toString() {
        return "Employee [empId=" + empId + ", empName=" + empName + "]";
    }

    @Override
    public int hashCode() {
        return empId + empName.hashCode();
    }

    @Override
    public boolean equals(Object obj) {

        if (this == obj) {
            return true;
        }
        if (!(this instanceof Employee)) {
            return false;
        }
        Employee emp = (Employee) obj;
        return this.getEmpId() == emp.getEmpId() && this.getEmpName().equals(emp.getEmpName());
    }

}

Класс теста

public class Test {

    public static void main(String[] args) {
        Employee emp1 = new Employee(101,"Manash");
        Employee emp2 = new Employee(101,"Manash");
        Employee emp3 = new Employee(103,"Ranjan");
        System.out.println(emp1.hashCode());
        System.out.println(emp2.hashCode());
        System.out.println(emp1.equals(emp2));
        System.out.println(emp1.equals(emp3));
    }

}

В объекте Class equals (Object obj) используется для сравнения сравнения адресов, поэтому, когда в классе Test, если вы сравниваете два объекта, тогда equals метод дает false, но когда мы переопределяем hashcode (), он может сравнивать контент и давать правильный результат.

2
ответ дан Suraj Rao 17 August 2018 в 11:12
поделиться
  • 1
    и класс тестирования I, добавленный в нижеприведенную программу. – Manash Ranjan Dakua 17 July 2018 в 10:40
  • 2
    В Object Class equals (Object obj) используется для сравнения сравнения адресов, поэтому, когда в классе Test, если вы сравниваете два объекта, тогда equals метод дает false, но когда мы переопределяем hashcode (), он может сравнивать контент и давать правильный результат. – Manash Ranjan Dakua 17 July 2018 в 10:44
  • 3
    вы можете использовать ссылку редактирования чуть ниже этого ответа, чтобы добавить свой ответ. Пожалуйста, не добавляйте ответ как два неполных – Suraj Rao 17 July 2018 в 11:34

Чтобы помочь вам проверять дубликаты объектов, нам нужны пользовательские значения equals и hashCode.

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

1
ответ дан Tavash 17 August 2018 в 11:12
поделиться

Добавление к ответу @Lombo

Когда вам нужно переопределить equals ()?

По умолчанию реализация equals () объекта равна

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

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

Но вы можете хотите рассмотреть два объекта одинаково, если они имеют одно и то же значение для одного или нескольких своих свойств (см. пример, приведенный в ответе @Lombo).

Итак, вы переопределите equals() в этих ситуациях, и вы дадите свои собственные условия для равенства.

Я успешно применил equals (), и он отлично работает. Так почему же они просят переопределить hashCode ()?

Хорошо. Пока вы не используете «Коллекции на основе хэша» определенный класс, это нормально. Но в будущем вы можете захотеть использовать HashMap или HashSet, и если вы не override и «правильно реализуете» hashCode () , эта коллекция на основе хэша не будет

Только переопределение равно (добавление к ответу @Lombo)

myMap.put(first,someValue)
myMap.contains(second); --> But it should be the same since the key are the same.But returns false!!! How?

Прежде всего, HashMap проверяет, является ли хэш-код second совпадает с first.

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

Поэтому даже не стоит проверять равенство.

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

Почему мы не можем сделать проверку HashMap равным во всех ведрах? Поэтому мне не нужно переопределять hashCode () !!

Тогда вам не хватает точки из Hash-based Collections. Рассмотрим следующее:

Your hashCode() implementation : intObject%9.

Ниже приведены ключи, хранящиеся в форме ведер.

Bucket 1 : 1,10,19,... (in thousands)
Bucket 2 : 2,20,29...
Bucket 3 : 3,21,30,...
...

Скажите, вы хотите знать, содержит ли карта ключ 10. Вы хотите найти все ведра? или Вы хотите искать только одно ведро?

На основании hashCode вы бы определили, что если 10 присутствует, он должен присутствовать в Bucket 1. Таким образом, будет поиск только Bucket 1 !!

5
ответ дан user104309 17 August 2018 в 11:12
поделиться
Другие вопросы по тегам:

Похожие вопросы: