Глубокая рекомендация утилиты клонирования [закрыто]


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

  • массивы
  • списки
  • карты

Примечание: предпочитаю некоторые решения без использования сериализации, но с использованием объекта.метод Clone. Я могу быть уверен, что мой пользовательский объект будет реализовывать метод clone() и будет использовать только стандартные классы java, которые можно клонировать...

8 66

8 ответов:

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

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

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

Так каково же решение:

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

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

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

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

клон

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

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

сериализовать

сериализация еще хуже; она имеет много недостатков 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. Преимущества:

  1. я могу решить, какой конструктор вызвать и как инициализировать поле.
  2. инициализация происходит в детерминированном порядке (корневой класс к классу экземпляра)
  3. я могу повторно использовать существующие объекты и заменить их
  4. тип safe
  5. синглтоны остановиться синглтоны

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

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

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

0.0851 ms : xstream (клонирование путем сериализации/десериализации)
0.0223 МС: двоичная сериализация (клонирование путем сериализации/десериализации)
0.0017 ms: cloner
* среднее время клонирования простого объекта (два поля) и отсутствие открытого конструктора по умолчанию. Бегите 10 000 раз.

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

  1. выполняет a глубокий клон любого объекта (даже тех, которые вы не пишете сами)
  2. вам не нужно обновлять метод clone () каждый раз, когда вы добавляете поле
  3. вы можете клонировать объекты, которые не имеют открытого конструктора по умолчанию
  4. работает с весны
  5. (оптимизация) не клонирует известные неизменяемые объекты (например, целое число, строку и т. д.)
  6. прост в использовании. Пример:

    клонирование.deepClone (anyObject);

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

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

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

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

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

можно использовать сериализация:

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

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

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

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

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

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