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

Переопределение метода equals и создание нового метода

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

Каков аргумент для и против переопределения метода equals?

4b9b3361

Ответ 1

Переопределение метода equals необходимо, если вы хотите проверить эквивалентность в стандартных классах библиотек (например, при условии, что java.util.Set содержит уникальные элементы или использует объекты как ключи в объектах java.util.Map).

Обратите внимание, что если вы переопределите равные, убедитесь, что вы выполняете контракт API, как описано в документации. Например, убедитесь, что вы также переопределили Object.hashCode:

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

EDIT: я не публиковал это как полный ответ на эту тему, поэтому я буду высказывать высказывание Фредрика Кальсета о том, что переопределение равных наилучшим образом подходит для неизменяемых объектов. Чтобы процитировать API для Map:

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

Ответ 2

Я очень рекомендую собрать копию Эффективной Java и прочитать через пункт 7, подчиняясь равному контракту. Вам нужно быть осторожным, если вы переопределяете равные для изменяемых объектов, так как многие из таких коллекций, как Карты и наборы, используют равные для определения эквивалентности, а мутация объекта, содержащегося в коллекции, может привести к неожиданным результатам. Брайан Гетц также имеет довольно хороший обзор реализации equals и hashCode.

Ответ 3

Вы должны "никогда" не переопределять equals и getHashCode для изменяемых объектов - это для .NET и Java. Если вы это сделаете и используете такой объект, как ключ в словаре f.ex, а затем измените этот объект, у вас будут проблемы, потому что словарь полагается на хэш-код для поиска объекта.

Вот хорошая статья по теме: http://weblogs.asp.net/bleroy/archive/2004/12/15/316601.aspx

Ответ 4

@David Schlosnagle упоминает упоминает Джоша Блоха Эффективная Java - это a обязательно читать для любого разработчика Java.

Существует связанная с этим проблема: для объектов неизменяемых значений вы также должны учитывать переопределение compare_to. Стандартная формулировка, если они отличаются, находится в Comparable API:

В общем случае, но строго не требуется, чтобы (ср. (x, y) == 0) == (x.equals(y)). Вообще говоря, любой компаратор, нарушающий это условие, должен четко указывать этот факт. Рекомендуемый язык: "Примечание: этот компаратор налагает упорядочения, которые не соответствуют равным".

Ответ 5

Метод Equals предназначен для сравнения ссылок. Поэтому не следует переоценивать изменение своего поведения.

Вы должны создать новый метод для проверки эквивалентности в разных случаях, если вам нужно (или использовать метод CompareTo в некоторых классах .NET)

Ответ 6

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

При этом вы также должны переопределить hashCode().

Подробнее см. здесь.

Ответ 7

Если честно, в Java нет никакого аргумента против переопределения равных. Если вам нужно сравнить примеры для равенства, то это то, что вы делаете.

Как упоминалось выше, вам нужно знать контракт с hashCode, и аналогичным образом следить за gotchas вокруг Comparable интерфейс - почти во всех ситуациях вы хотите, чтобы естественное упорядочение, определенное как Comparable, соответствовало равенствам (см. BigDecimal api doc для пример канонического счетчика)

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