Мне нравится этот вопрос! В основном потому, что на него почти никогда не отвечают или плохо отвечают. Вроде еще никто не понял. Девственная территория :)
Во-первых, даже не думайте об использовании equals
. Контракт equals
, как определено в javadoc, является отношением эквивалентности (рефлексивным, симметричным и транзитивным), а не отношением равенства. Для этого он также должен быть антисимметричным. Единственная реализация equals
этого отношения (или когда-либо могло бы быть) истинное отношение равенства - это отношение в java.lang.Object
. Даже если вы все-таки использовали equals
для сравнения все на графике, риск разрыва контракта довольно высок. Как указал Джош Блох в Эффективной Java , контракт равных очень легко нарушить:
«Просто нет способа расширить инстанцируемый класс и добавить аспект, сохранив при этом контракт равенства»
Кроме того, какая польза от логического метода в любом случае? Было бы неплохо на самом деле инкапсулировать все различия между оригиналом и клоном, не так ли? Кроме того, я предполагаю, что вы не хотите беспокоиться о написании / поддержке кода сравнения для каждого объекта на графике, а скорее ищете что-то, что будет масштабироваться вместе с исходным кодом, поскольку он изменяется с течением времени.
То, что вам действительно нужно, это какой-то инструмент для сравнения состояний. То, как этот инструмент реализован, действительно зависит от природы вашей модели предметной области и ваших ограничений производительности. По моему опыту, универсальной волшебной пули не существует. И это будет медленным на большом количестве итераций. Но для проверки полноты операции клонирования он отлично справится со своей задачей. Два ваших лучших варианта - это сериализация и отражение.
Некоторые проблемы, с которыми вы столкнетесь:
- Порядок коллекций: следует ли считать две коллекции похожими, если они содержат одни и те же объекты, но в разном порядке?
- Какие поля игнорировать: временные? Статический?
- Эквивалентность типов: должны ли значения полей быть одного и того же типа? Или одно может расширять другое?
- Есть еще кое-что, но я забыл ...
XStream работает довольно быстро и в сочетании с XMLUnit выполнит работу всего за несколько строк кода. XMLUnit хорош тем, что может сообщать обо всех различиях или просто останавливаться на первом найденном. И его вывод включает xpath к разным узлам, что приятно. По умолчанию он не разрешает неупорядоченные коллекции, но его можно настроить для этого. Внедрение специального обработчика различий (называемого a DifferenceListener
) позволяет указать способ обработки различий, включая игнорирование порядка. Однако, как только вы захотите сделать что-либо, кроме простейшей настройки, становится трудно писать, и детали, как правило, привязаны к определенному объекту предметной области.
Лично я предпочитаю использовать отражение для циклического перебора всех объявленных полей и детализации каждого из них, отслеживая различия по мере продвижения. Предупреждение: не используйте рекурсию, если вам не нравятся исключения переполнения стека. Держите вещи в области видимости с помощью стека (используйтеLinkedList
или что-то). Я обычно игнорирую временные и статические поля, и я пропускаю пары объектов, которые я уже сравнивал, поэтому я не попадаю в бесконечные циклы, если кто-то решил написать самореферентный код (однако я всегда сравниваю примитивные оболочки, независимо от того, что , поскольку одни и те же ссылки на объекты часто используются повторно). Вы можете настроить все заранее, чтобы игнорировать порядок сбора и игнорировать специальные типы или поля, но мне нравится определять свои политики сравнения состояний для самих полей с помощью аннотаций. Это, IMHO, именно для этого и предназначались аннотации, чтобы сделать метаданные о классе доступными во время выполнения. Что-то вроде:
@StatePolicy(unordered=true, ignore=false, exactTypesOnly=true)
private List<StringyThing> _mylist;
Я думаю, что это действительно сложная проблема, но полностью решаемая! И если у вас есть что-то, что работает для вас, это действительно очень удобно :)
Удачи. И если вы придумаете что-то гениальное, не забудьте поделиться!