Вопрос

Этот вопрос конкретно связан с переопределением метода equals() для объектов с большим количеством полей.Прежде всего, позвольте мне сказать, что этот большой объект не может быть разбит на несколько компонентов без нарушения принципов OO, поэтому указание мне "ни один класс не должен иметь больше x полей" не поможет.

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

--code removed because it was too distracting--

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

Плюсы:

  • Если добавляется новое поле, оно включается автоматически
  • Этот метод гораздо более лаконичен, чем 30 операторов if

Минусы:

  • Если добавляется новое поле, оно включается автоматически, иногда это нежелательно
  • Производительность:Это должно быть медленнее, я не чувствую необходимости запускать профилировщик
  • Внесение в белый список определенных полей, которые следует игнорировать при сравнении, немного некрасиво

Есть какие-нибудь мысли?

Это было полезно?

Решение

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

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

P.P.S.Я надеюсь, вы уже все обдумали Конструктор хэшкодов и Эквалсбилдер.

Другие советы

Используй Eclipse, FFS!

Удалите хэш-код и методы equals, которые у вас есть.

Щелкните правой кнопкой мыши на нужном файле.

Выберите Source-> Сгенерировать хэш-код и equals...

Сделано!Больше не беспокойтесь об отражении.

Повторите для каждого добавленного поля, вы просто используете представление структуры, чтобы удалить свои два метода, а затем позволяете Eclipse автоматически сгенерировать их.

Если вы придерживаетесь рефлексивного подхода, EqualsBuilder по-прежнему остается вашим другом:

 public boolean equals(Object obj) {
    return EqualsBuilder.reflectionEquals(this, obj);
 }

Вот мысль, если вы беспокоитесь о:

1 / Забываете обновить свою большую серию if-операторов для проверки равенства при добавлении / удалении поля.

2 / Эффективность выполнения этого в методе equals().

Попробуйте следующее:

a / Вернитесь к использованию длинной последовательности if-операторов в вашем методе equals().

b / Иметь единственную функцию, которая содержит список полей (в строковом массиве) и которая будет проверять этот список на соответствие действительности (т. е. отраженным полям).Он выдаст исключение, если они не совпадут.

c / В вашем конструкторе для этого объекта есть синхронизированный однократный вызов этой функции (аналогично одноэлементному шаблону).Другими словами, если это первый объект, созданный этим классом, вызовите функцию проверки, описанную в (b) выше.

Исключение сразу станет очевидным при запуске вашей программы, если вы не обновили свои if-инструкции, чтобы они соответствовали отраженным полям;затем вы исправляете if-инструкции и обновляете список полей из (b) выше.

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

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

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

Вы всегда можете аннотировать поля, которые вам нужны / не нужны в вашем методе equals, это должно быть простым изменением в нем.

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

Кроме того, говоря о хэш-картах, у вас такая же проблема с методом hashCode.

Наконец, вам действительно нужно сравнивать все поля на предмет равенства?

У вас есть несколько ошибок в вашем коде.

  1. Вы не можете предполагать , что this и obj являются одним и тем же классом.Действительно, это явно разрешено для obj быть любым другим классом.Вы могли бы начать с if ( ! obj instanceof myClass ) return false; однако это все еще неверно потому что obj может быть подклассом this с дополнительными полями, которые могут иметь значение.
  2. Вы должны поддержать null значения для obj с помощью простого if ( obj == null ) return false;
  3. Ты не можешь лечить null и пустая строка как равная.Вместо этого лечите null особенно.Самый простой способ здесь - начать с сравнения Field.get(obj) == Field.get(this).Если они оба равны или оба случайно указывают на один и тот же объект, это происходит быстро.(Примечание:Это также оптимизация, которая вам нужна, поскольку это медленная процедура.) Если это не удается, вы можете использовать быстрый if ( Field.get(obj) == null || Field.get(this) == null ) return false; для обработки случаев, когда точно один из них является null.Наконец, вы можете использовать обычный equals().
  4. Ты не используешь foundMismatch

Я согласен с Хэнком в том, что [HashCodeBuilder][1] и [EqualsBuilder][2] это лучший способ уйти.Он прост в обслуживании, не содержит большого количества шаблонного кода, и вы избегаете всех этих проблем.

Вы могли бы использовать аннотации, чтобы исключить поля из проверки

например ,

@IgnoreEquals
String fieldThatShouldNotBeCompared;

И затем, конечно, вы проверяете наличие аннотации в вашем общем методе equals.

Если у вас есть доступ к названиям полей, почему бы вам не установить стандарт, согласно которому поля, которые вы не хотите включать, всегда начинаются с "local" или "nochk" или что-то в этом роде.

Затем вы заносите в черный список все поля, которые начинаются с этого (тогда код не такой уж уродливый).

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top