Вопрос-ответ

Java: recommended solution for deep cloning/copying an instance

Java: рекомендуемое решение для глубокого клонирования / копирования экземпляра

Мне интересно, есть ли рекомендуемый способ выполнить глубокое клонирование / копирование экземпляра в java.

У меня есть на примете 3 решения, но я могу пропустить некоторые, и я хотел бы узнать ваше мнение

редактировать: включить предложение Bohzo и уточнить вопрос: речь идет скорее о глубоком клонировании, чем о поверхностном.

Сделай это сам:

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

профессиональный:
- контроль того, что будет выполняться
- быстрое выполнение

минусы:
- утомительно писать и поддерживать
- подвержен ошибкам (ошибка копирования / вставки, отсутствующее свойство, переназначенное изменяемое свойство)

Используйте отражение:

С помощью ваших собственных инструментов отражения или внешнего помощника (например, jakarta common-beans) легко написать универсальный метод копирования, который выполнит работу в одной строке.

профессиональный:
- простота написания
- отсутствие обслуживания

минусы:
- меньший контроль над тем, что происходит
- подвержен ошибкам с изменяемым объектом, если инструмент отражения не клонирует подобъекты тоже
- более медленное выполнение

Используйте clone Framework:

Используйте фреймворк, который сделает это за вас, например :

commons-lang SerializationUtils

Библиотека глубокого клонирования Java

Dozer

Kryo

профессиональный:
- то же, что и отражение
- больше контроля над тем, что именно будет клонировано.

минусы:
- каждый изменяемый экземпляр полностью клонируется, даже в конце иерархии
- выполнение может быть очень медленным

Используйте инструментарий байт-кода для написания clone во время выполнения

javassit, BCEL или cglib могут использоваться для создания выделенного клонировщика так быстро, как это делается одной рукой. Кто-нибудь знает библиотеку, использующую один из этих инструментов для этой цели?

Что я здесь пропустил?
Что бы вы порекомендовали?

Спасибо.

Переведено автоматически
Ответ 1

Для глубокого клонирования (клонирует всю иерархию объектов):


  • commons-lang SerializationUtils - использование сериализации - если все классы находятся под вашим контролем и вы можете принудительно реализовать Serializable.


  • Библиотека глубокого клонирования Java - использование отражения - в случаях, когда классы или объекты, которые вы хотите клонировать, находятся вне вашего контроля (библиотека сторонних производителей) и вы не можете заставить их реализовать Serializable, или в случаях, когда вы не хотите реализовывать Serializable.


Для мелкого клонирования (клонирует только свойства первого уровня):


  • commons-beanutils BeanUtils - в большинстве случаев.


  • Spring BeanUtils - если вы уже используете spring и, следовательно, имеете эту утилиту в classpath.


Я намеренно опустил опцию "сделай сам" - приведенные выше API обеспечивают хороший контроль над тем, что клонировать, а что нет (например, используя transient, или String[] ignoreProperties), поэтому изобретать велосипед нецелесообразно.

Ответ 2

В книге Джошуа Блоха есть целая глава, озаглавленная "Пункт 10: разумно переопределять клонирование", в которой он объясняет, почему переопределение clone по большей части является плохой идеей, потому что спецификация Java для этого создает много проблем.

Он предлагает несколько альтернатив:


  • Используйте фабричный шаблон вместо конструктора:


         public static Yum newInstance(Yum yum);

  • Используйте конструктор копирования:


         public Yum(Yum yum);

Все классы коллекций в Java поддерживают конструктор копирования (например, new ArrayList(l);)

Ответ 3

Начиная с версии 2.07 Kryo поддерживает мелкое / глубокое клонирование:

Kryo kryo = new Kryo();
SomeClass someObject = ...
SomeClass copy1 = kryo.copy(someObject);
SomeClass copy2 = kryo.copyShallow(someObject);

Kryo работает быстро, на их странице и вы можете найти список компаний, которые используют его в производстве.

Ответ 4

Используйте XStream ToXML / fromXML в памяти. Чрезвычайно быстрый, существует уже давно и успешно развивается. Объекты не обязательно должны быть сериализуемыми, и вам не нужно использовать отражение (хотя XStream использует). XStream может распознавать переменные, указывающие на один и тот же объект, и не создавать случайно две полные копии экземпляра. За эти годы было разработано множество подобных деталей. Я использую его в течение ряда лет, и к нему можно перейти. Он настолько прост в использовании, насколько вы можете себе представить.

new XStream().toXML(myObj)

или

new XStream().fromXML(myXML)

Для клонирования,

new XStream().fromXML(new XStream().toXML(myObj))

Более кратко:

XStream x = new XStream();
Object myClone = x.fromXML(x.toXML(myObj));
java