Этот вопрос конкретно связан с переопределением метода equals () для объектов с большим количеством полей. Прежде всего, позвольте мне сказать, что этот большой объект не может быть разбит на несколько компонентов без нарушения принципов объектно-ориентированного программирования, поэтому сообщение мне, что «ни один класс не должен иметь более x полей», не поможет.
Дальше проблема решилась, когда я забыл проверить одно из полей на равенство. Следовательно, мой метод equals был неверным. Тогда я подумал использовать отражение:
--code removed because it was too distracting--
Цель этой публикации не обязательно в рефакторинге кода (это даже не тот код, который я использую), а в том, чтобы получить информацию о том, является ли это хорошей идеей.
Плюсы:
Минусы:
Какие-нибудь мысли?




Если вы действительно хотите внести в белый список по соображениям производительности, рассмотрите возможность использования аннотации, чтобы указать, какие поля для сравнения. Кроме того, эта реализация не будет работать, если в ваших полях нет хороших реализаций для equals().
P.S. Если вы выберете этот путь для equals(), не забудьте сделать что-то подобное для hashCode().
P.P.S. Надеюсь, вы уже рассматривали HashCodeBuilder и EqualsBuilder.
Это зависит от того, что вы считаете наиболее вероятным: добавить поле и забыть добавить его в equals () или добавить поле, которое вы не хотите и / или не можете использовать в автоматическом сравнении, хотя использование аннотации может помочь. Вы можете рассмотреть что-то вроде flexjson и сравнить вывод каждого объекта.
Вы всегда можете аннотировать поля, которые вам нужны / не нужны в вашем методе equals, это должно быть простым и простым изменением для него.
Производительность, очевидно, связана с тем, как часто объект фактически сравнивается, но многие фреймворки используют хэш-карты, поэтому ваши равные могут использоваться чаще, чем вы думаете.
Кроме того, говоря о хэш-картах, у вас есть та же проблема с методом hashCode.
Наконец, действительно ли вам нужно сравнивать все поля на предмет равенства?
Я на самом деле оговорился, у нас есть метод hashcode / equals, который просто использует идентификатор записи (из базы данных), и поскольку он всегда будет уникальным, метод hashCode / equals просто сравнивает идентификаторы. Но нам нужно проверить, эквивалентны ли объекты, если все поля одинаковы.
Если у вас есть доступ к именам полей, почему бы вам не сделать стандартом, что поля, которые вы не хотите включать, всегда начинаются с «local», «nochk» или чего-то в этом роде.
Затем вы заносите в черный список все поля, которые начинаются с этого (тогда код не такой уж уродливый).
Я не сомневаюсь, что он немного медленнее. Вам необходимо решить, хотите ли вы поменять местами простоту обновления и скорость выполнения.
Я думаю, что добавление соглашений для чего-то вроде этого излишне снижает удобочитаемость.
В вашем коде есть несколько ошибок.
this и obj относятся к одному классу. Действительно, для obj явно разрешено быть любым другим классом. Вы можете начать с if ( ! obj instanceof myClass ) return false;, но это все еще не правильно, потому что obj может быть подклассом this с дополнительными полями, которые могут иметь значение.null для obj с помощью простого if ( obj == null ) return false;null и пустую строку как равные. Вместо этого обращайтесь с null специально. Самый простой способ - начать со сравнения Field.get(obj) == Field.get(this). Если они оба равны или оба указывают на один и тот же объект, это быстро. (Примечание: это также оптимизация, которая вам нужна, поскольку это медленная процедура.) Если это не удается, вы можете использовать быстрый if ( Field.get(obj) == null || Field.get(this) == null ) return false; для обработки случаев, когда ровно один из них - null. Наконец-то можно использовать обычный equals().foundMismatchЯ согласен с Хэнком, что [HashCodeBuilder][1] и [EqualsBuilder][2] - лучший вариант. Его легко поддерживать, не нужно много шаблонного кода, и вы избегаете всех этих проблем.
Взгляните на org.apache.commons.EqualsBuilder:
Вот мысль, если вас беспокоит:
1 / Забыть обновить большую серию операторов if для проверки равенства при добавлении / удалении поля.
2 / Производительность этого в методе equals ().
Попробуйте следующее:
a / Вернитесь к использованию длинной последовательности операторов if в вашем методе equals ().
б / иметь единственную функцию, которая содержит список полей (в массиве String) и которая будет проверять этот список на соответствие действительности (т.е. отраженным полям). Если они не совпадают, генерируется исключение.
c / В конструкторе этого объекта используйте синхронизированный однократный вызов этой функции (аналогично одноэлементному шаблону). Другими словами, если это первый объект, созданный этим классом, вызовите функцию проверки, описанную в пункте (b) выше.
Исключение сразу станет очевидным при запуске программы, если вы не обновили операторы if, чтобы они соответствовали отраженным полям; затем вы исправляете операторы if и обновляете список полей из пункта (b) выше.
Последующее построение объектов не будет выполнять эту проверку, и ваш метод equals () будет работать с максимально возможной скоростью.
Как я ни старался, я не смог найти никаких реальных проблем с этим подходом (в StackOverflow могут существовать большие умы) - есть дополнительная проверка условий для каждой конструкции объекта для поведения однократного запуска, но это кажется довольно незначительным.
Если вы достаточно постараетесь, вы все равно можете получить ваши if-выражения не в соответствии с вашим списком полей и отраженными полями, но исключение гарантирует, что ваш список полей соответствует отраженным полям, и вы просто убедитесь, что обновили if-выражения и поле список одновременно.
Если вы выберете подход отражения, EqualsBuilder по-прежнему будет вашим другом:
public boolean equals(Object obj) {
return EqualsBuilder.reflectionEquals(this, obj);
}
Вы можете использовать аннотации, чтобы исключить поля из проверки
например
@IgnoreEquals
String fieldThatShouldNotBeCompared;
И затем, конечно, вы проверяете наличие аннотации в вашем универсальном методе equals.
Используйте Eclipse, FFS!
Удалите имеющиеся у вас методы hashCode и equals.
Щелкните файл правой кнопкой мыши.
Выберите Source-> Generate hashcode and equals ...
Сделанный! Больше не беспокойтесь об отражении.
Повторите эти действия для каждого добавленного поля, вы просто используете вид схемы, чтобы удалить два ваших метода, а затем позволить Eclipse автоматически сгенерировать их.
Хотя этот метод проще, чем писать вручную, он разделяет основные недостатки как рефлексивных, так и ручных методов. Метод все еще может быть устаревшим, когда добавляются поля, а метод не создается повторно, и поля все еще можно проверять, чего не должно быть, когда кто-то регенерирует метод и забывает удалить проверку.
Иногда волшебной пули нет. Но самое простое решение - это, как правило, самый простой способ в таких случаях.
Все поля являются строками или примитивами @ P.S. Уже сделал, но напомнить всем не помешает! @ P.P.S. Я знал, что что-то там должно быть. Я использовал ToStringBuilder, понятия не имею, как я это упустил. Настоящий вопрос - размышлять или не размышлять.