2008-09-23 3 views
9

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

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

--code removed because it was too distracting-- 

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

Плюсы:

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

Минусы:

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

Любые мысли?

ответ

13

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

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

P.P.S. Надеюсь, вы уже рассмотрели HashCodeBuilder и EqualsBuilder.

+0

Все поля являются строками или примитивами @ P.S. Это уже делалось, но не повредить, чтобы напомнить всем! @ P.P.S. Я знал, что там должно быть что-то. Я использовал ToStringBuilder, я понятия не имею, как я их игнорировал. Настоящий вопрос состоит в том, чтобы отражать или не отражать. – oreoshake 2008-09-23 23:52:05

+0

Это зависит от того, что, по вашему мнению, наиболее вероятно: добавление поля и забывание добавить его к equals() или добавление поля, которое вы не хотите и/или не можете использовать в автоматическом сравнении, хотя использование аннотации может помочь , Вы можете рассмотреть что-то вроде flexjson и сравнить результат каждого объекта. – 2008-09-24 01:19:18

+0

Эти строители довольно круты. – 2008-09-24 11:45:56

1

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

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

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

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

+0

Я действительно оговорюсь, у нас есть метод hashcode/equals, который просто использует идентификатор записи (из db), и поскольку это всегда будет уникальным, метод hashCode/equals просто сравнивает идентификаторы. Но нам нужно проверить, являются ли объекты равнозначными, каждое поле будет одинаковым. – oreoshake 2008-09-23 23:56:28

0

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

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

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

1

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

  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] является лучшим способом пойти. Это легко поддерживать, а не много шаблонов кода, и вы избегаете всех этих проблем.

2

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

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

2/Выполнение этого в методе equals().

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

а/Откат назад, используя длинную последовательность метода, если-заявления в ваших Equals().

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

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

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

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

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

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

5

Если идти подход отражения, EqualsBuilder еще ваш друг:

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

Вы можете использовать аннотации для исключения полей из проверки

например

@IgnoreEquals 
String fieldThatShouldNotBeCompared; 

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

9

Использование Eclipse, FFS!

Удалить методы hashCode и equals, которые у вас есть.

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

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

Готово! Больше не беспокоиться об отражении.

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

Смежные вопросы