Рекомендация утилиты Deep clone

Есть ли какая-либо утилита для глубокого клонирования для коллекций java:

  • Массивы
  • Списки
  • Карты

ПРИМЕЧАНИЕ. Предпочитайте некоторое решение без использования сериализации, но с использованием метода Object.clone(). Я могу быть уверен, что мой пользовательский объект реализует метод clone() и будет использовать только классы java-standard, которые являются клонируемыми...

Ответ 1

Я думаю, что предыдущий зеленый ответ был плохим, почему вы можете спросить?

  • Он добавляет много кода
  • Он требует, чтобы вы перечислили все поля, которые нужно скопировать, и сделайте это
  • Это не будет работать для списков при использовании clone() (Это то, что clone() для HashMap говорит: возвращает неглубокую копию этого экземпляра HashMap: ключи и ценности не клонированы.), Поэтому вы в конечном итоге делаете это вручную (это заставляет меня плакать)

О, и, кстати, сериализация также плоха, вам может потребоваться добавить Serializable по всему месту (это также заставляет меня плакать).

Итак, какое решение:

Библиотека глубокого клонирования Java Библиотека клонирования - небольшая библиотека Java с открытым исходным кодом (apache license), которая глубоко клонирует объекты. Объектам не нужно реализовывать интерфейс Cloneable. Эффективно, эта библиотека может клонировать ЛЮБЫЕ java-объекты. Его можно использовать, то есть в реализациях кеша, если вы не хотите, чтобы кешированный объект был изменен или когда вы хотите создать глубокую копию объектов.

Cloner cloner=new Cloner();
XX clone = cloner.deepClone(someObjectOfTypeXX);

Проверьте это на https://github.com/kostaskougios/cloning

Ответ 2

Все подходы к копированию объектов в Java имеют серьезные недостатки:

Clone

  • Метод clone() защищен, поэтому вы не можете вызывать его напрямую, если класс, о котором идет речь, не переопределяет его общедоступным методом.
  • clone() не вызывает конструктор. Любой конструктор. Он будет выделять память, назначить внутреннее поле class (которое вы можете прочитать через getClass()) и скопировать поля оригинала.

Дополнительные вопросы с clone() см. в пункте 11 книги Джошуа Блоха " Эффективная Java, второе издание"

Serialize

Сериализация еще хуже; он имеет множество недостатков clone(), а затем некоторые. У Джошуа есть целая глава с четырьмя пунктами только для этой темы.

Мое решение

Мое решение добавляет новый интерфейс к моим проектам:

public interface Copyable<T> {
    T copy ();
    T createForCopy ();
    void copyTo (T dest);
}

Код выглядит следующим образом:

class Demo implements Copyable<Demo> {
    public Demo copy () {
        Demo copy = createForCopy ();
        copyTo (copy);
        return copy;
    }
    public Demo createForCopy () {
        return new Demo ();
    }
    public void copyTo (Demo dest)
        super.copyTo (dest);
        ...copy fields of Demo here...
    }
}

К сожалению, мне нужно скопировать этот код ко всем моим объектам, но он всегда тот же код, поэтому я могу использовать шаблон редактора Eclipse. Преимущества:

  • Я могу решить, какой конструктор вызвать и как инициализировать это поле.
  • Инициализация происходит в детерминированном порядке (класс root для класса экземпляра)
  • Я могу повторно использовать существующие объекты и перезаписать их
  • Тип безопасного
  • Синглоты остаются синглонами

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

Ответ 3

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

Как и этот ответ, я использовал библиотеку Cloner и в частности, производительность протестировала его против XStream (который может "клонировать" путем сериализации, затем десериализации) и двоичной сериализации. Хотя XStream очень быстро выполняет сериализацию в/из xml, Cloner намного быстрее при клонировании:

0,0851 мс: xstream (клон путем сериализации/десериализации)
0.0223 мс: двоичная сериализация (клонирование путем сериализации/десериализации)
0.0017 ms: cloner
* среднее время клонирования простого объекта (два поля) и стандартного конструктора public. Запустите 10000 раз.

В дополнение к быстрому, здесь больше причин выбирать клонирование:

  • выполняет глубокий клон любого объекта (даже те, которые вы не пишете сами)
  • Вам не нужно постоянно обновлять метод clone() каждый раз, когда вы добавляете поле
  • вы можете клонировать объекты, не имеющие общедоступного конструктора по умолчанию
  • работает с Spring
  • (оптимизация) не клонирует известные неизменяемые объекты (например, Integer, String и т.д.).
  • проста в использовании. Пример:

    cloner.deepClone(anyObject);

Ответ 4

Я создатель клонирования lib, тот, который представил Брэд. Это решение для клонирования объектов без необходимости писать дополнительный код (нет необходимости в сериализуемых объектах или методе impl clone())

Это довольно быстро, как сказал Брэд, и недавно я загрузил версию, которая еще быстрее. Обратите внимание, что ручное внедрение метода clone() будет быстрее, чем clone lib, но затем вам нужно будет написать много кода.

Cloner lib работал у меня хорошо, так как я использую его в реализации кэша для сайта с очень интенсивным трафиком (~ 1 млн запросов/день). Кэш должен клонировать приблизительно 10 объектов на запрос. Он достаточно надежный и стабильный. Но, пожалуйста, имейте в виду, что клонирование не без риска. Lib может быть настроен для печати каждого экземпляра класса, который он клонирует во время dev. Таким образом, вы можете проверить, клонирует ли он то, что, по вашему мнению, нужно клонировать, - графы объектов могут быть очень глубокими и содержать ссылки на удивительно большое количество объектов. С помощью clone lib вы можете поручить ему не клонировать объекты, которые вы не хотите, т.е. Одиночные.

Ответ 5

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

Отметьте ответ Бруно для ссылки на классы утилиты сериализации Apache Commons, что будет очень полезно, если это маршрут, который вы решите принять.

Ответ 6

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

Apache Commons предоставляет SerializationUtils

Ответ 8

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

Чтобы получить его вкус, вот пример класса:

public class CloneMePlease {
    @Clone(Skip.class)
    String id3 = UUID.randomUUID().toString();

    @Clone(Null.class)
    String id4 = UUID.randomUUID().toString();

    @Clone(value = RandomUUID.class, groups=CustomActivationGroup1.class)
    String id5 = UUID.randomUUID().toString();

    @Clone.List({
            @Clone(groups=CustomActivationGroup2.class, value=Skip.class),
            @Clone(groups=CustomActivationGroup3.class, value=Copy.class)})
    Object activationGroupOrderTest = new Object();

    @Clone(LongIncrement.class)
    long version = 1l;

    @PostClone
    private void postClone(CloneMePlease original, @CloneInject CloneInjectedService service){
         //do stuff with the original source object in the context of the cloned object
         //you can inject whatewer service you want, from spring/guice to perform custom logic here
    }
}

Подробнее здесь: https://github.com/mnorbi/fluidity-cloning

В случае, если он нужен, существует также расширение спящего режима.

Ответ 9

Используйте сериализацию, а затем десериализацию, но имейте в виду, что этот подход работает только с классами Serializable без временных полей. Кроме того, ваши синглтоны больше не будут синглетами.

Ответ 10

Theres хорошая библиотека, которая делает глубокие клоны полезными для деактивированных объектов из сеансов спящего режима.

http://sourceforge.net/projects/cloneutils/