Это немного сложно;Я должен объяснить несколько вещей о том, как работает метод equals и hashCode для объяснения жизнеспособных решений.
Существует «контракт».Компилятор не может применить его, но если вы не будете придерживаться этого контракта, произойдут странные вещи.В частности: Ваши объекты будут просто делать что-то не то, когда используются в качестве ключей в хэш-картах, и, возможно, другие подобные проблемы при использовании сторонних библиотек.Чтобы должным образом придерживаться контракта, любой данный класс либо должен полностью отказаться от equals / hashCode, либо OR, всей цепочке (таким образом, класс и все его подклассы) должны корректно переопределить hashCode и equals, за исключением того, что вы действительно можете 'не делайте этого, если только родитель не получает соответствующих инструкций.
В договоре указано, что это всегда должно быть правильно:
- a.equals (b) -> b.equals (a).
- a.equals (b) и b.equals (c) -> a.equals (c).
- a.equals (a).
- a.equals (b) -> a.hashCode () == b.hashCode ().(обратите внимание, что обратное не обязательно должно быть правдой; одинаковые хеш-коды не означают, что объекты равны).
Контракт ДЕЙСТВИТЕЛЬНО трудно гарантировать перед лицом иерархии классов!Представьте, что мы берем существующий java.util.ArrayList и создаем его подкласс с понятием «цвет».Так что теперь у нас может быть синий ColoredArrayList или красный ColoredArrayList.Было бы разумно сказать, что синий ColoredArrayList определенно НЕ должен равняться красному ColoredArrayList, за исключением того, что ... равно значению самого ArrayList (который вы не можете изменить), фактически определяет, что вы просто не можете расширять ArrayList с помощью свойств, подобных этому вообще : если вы вызываете a.equals (b), где a - пустой массив, а b - какой-то пустой список (скажем, пустой красный ColoredArrayList), он просто проверит равенство каждого члена в нем, что,учитывая, что они оба пусты, это тривиально верно.Таким образом, пустой нормальный массив ArrayList равен как пустому красному, так и пустому синему ColoredArrayList, и поэтому в контракте предусматривалось, что пустой красный ColoredArrayList должен совпадать с пустым синим ColoredArrayList.В этом смысле сонар здесь просто сломан.Есть проблема, и она не решаема. Невозможно написать концепцию ColoredArrayList в java .
Тем не менее, решение есть, но только если каждый класс в иерархии находится на борту.Это canEqual
подход.Выход из цветной дилеммы, описанный выше, состоит в том, чтобы дифференцировать понятия «Я расширяю и добавляю новые свойства» и «Я расширяю, но эти вещи все еще семантически говорят о том же, что и без новых свойств».ColoredArrayList - первый случай: это расширение, которое добавляет новые свойства.Идея canEqual заключается в том, что вы создаете отдельный метод для указания этого, что позволяет ArrayList выяснить: я не могу быть равен ЛЮБОМУ экземпляру ColoredArrayList, даже если все элементы одинаковы.Тогда мы можем снова придерживаться договора.ArrayList НЕ имеет этой системы на месте, и, следовательно, учитывая, что вы не можете изменить исходный код ArrayList, вы застряли: это невозможно исправить.Но если вы напишите свою собственную иерархию классов, вы можете добавить ее.
Project Lombok позаботится о том, чтобы добавить для вас equals и hashCode.Даже если вы не хотите его использовать, вы можете посмотреть, что он генерирует, и продублировать его в своем собственном коде.Это также удалит предупреждения, которые испускает сонар.См. https://projectlombok.org/features/EqualsAndHashCode - здесь также показано, как можно использовать концепцию canEqual
, чтобы избежать дилеммы ColoredArrayList.
Здесь вы создаете подкласс без добавления новых свойств, поэтому нет необходимости заменять hashCodeи равно.Но сонар этого не знает.