В этой статье будут обсуждаться следующие 4 вопроса
1. Java Clonable Interface реализует глубокую копию
2. Сериализация Java реализует глубокую копию
3. Самый быстрый анализ исходного кода клонирования библиотеки библиотеки
4. Сравнение скоростей нескольких методов копирования
Я не буду говорить о концепции глубокой копии в этой статье. Реализация глубокой копии в C ++. Как правило, перегрузить оператор назначения "=" для реализации глубокой копии между объектами того же класса. Следовательно, вполне естественно, что в Java мы также можем определить функцию копирования, чтобы назначить каждое свойство объекта в функции. Этот метод прост и естественно, но есть фатальная проблема: если один день новый атрибут, который требует глубокой копии, добавляется в класс, соответствующая функция копирования также должна быть изменена. Этот метод приносит большие неудобства для расширения класса. Как решить эту проблему, давайте посмотрим на метод реализации главах 1, 2 и 3 и скорость теста раздела 4.
1. Клонируемый интерфейс Java реализует Deep Copy <Br /> Таким образом, класс должен реализовать функцию клона с окрашимым интерфейсом и вызов Super.clone в функции клона. Эта глубокая копия метода также приносит другую проблему. Если в классе есть объекты других классов в качестве свойств, другие классы также должны быть перегружены и реализованы в интерфейсе клонируемого. Вот пример. В следующем примере ComplexDO содержит объекты Simpledo. Для реализации Deep Copy SpextDo вам необходимо сначала реализовать интерфейс Clone Simpledo:
Общедоступный класс Simpledo реализует клонируемый, сериализуемый {private int x = 1; Приватная строка s = "simpledo"; @Override Protected Object Clone () бросает ClonenotSupportedException {Simploedo newclass = (simpledo) super.clone (); вернуть NewClass; }} public Class Complexdo реализует клонируемые, сериализуемые {private int x = 1; частная строка s = "комплекс"; частное целое число A = 123; частное целое число B = 1234; частное целое число C = 1334455; частная строка S2 = "хе -хе"; частная строка S3 = "хахаха"; Приватный длинный идентификатор = 1233245L; Private ArrayList <Simploedo> l = новый ArrayList <Simpledo> (); @Override public Object Clone () бросает ClonenotSupportedException {Speckleydo newclass = (SpecblerDo) super.clone (); newClass.l = new ArrayList <Simpledo> (); для (Simploedo Simple: this.l) {newclass.l.add ((simpledo) simple.clone ()); } вернуть NewClass; }} Следует отметить, что во многих статьях говорится, что оператор назначения типа строки является глубокой копией, но на самом деле те, кто использует операторы назначения в Java, являются мелкими копиями, но почему статьи с такими очевидными ошибками должны сказать, что это глубокая копия? Насколько я понимаю, что атрибуты строки и типа являются основными типами, а предоставляемый метод будет новым объектами, если будут разработаны внутренние изменения данных. Следовательно, операция строки не повлияет на память, на которую она первоначально указала. Следовательно, вообще говоря, операции назначения основных классов, таких как строка, являются глубокими копиями.
По этой причине при использовании сплайсинга строкости необходимо открыть новую память, поэтому многие люди рекомендуют использовать StringBuilder вместо строки для сплайсинга, потому что StringBuilder повторно применяет большую память, когда встроенный диапазон массива ChAR не достаточно (для современных JVMS, код будет настроен, а строка+строка будет оптимизирован в сходные инструкции для StringBuilder.Append). Для обрезки, противоположного сплайсингу, в строке существует функция подстроки. При использовании функции подстроения внутренний массив char новой строки такой же, как исходная строка? Это более интересно. Если вы заинтересованы, вы можете сравнить и проверить реализацию JDK1.6 и JKD1.7.
2. Сериализация Java реализует глубокую копию
Принцип этого метода состоит в том, чтобы использовать сериализацию Java для сериализации объекта в бинарный байтовый поток, а затем покинуть и присвоить значение объекту. Пример кода:
public Object Seircopy (Object src) {try {bytearrayoutputstream byteout = new BytearrayOutputStream (); ObjectOutputStream OUT = new ObjectOutputStream (ByteOut); out.writeobject (src); BytearrayinputStream bytein = new Bytearrayinputstream (byteout.tobytearray ()); ObjectInputStream in = new ObjectInputStream (bytein); Object dest = in.ReadObject (); вернуть Дест; } catch (Exception e) {// сделать какой -то обработчик ошибок return null; }} Конечно, вы также можете использовать JSON и другие сериализованные библиотеки для завершения сериализации. Этот метод эффективно избегает расширяемых недостатков границы интерфейса Cloneabel. Функция может быть в основном подходящей для всех классов. Недостатком является то, что это относительная копия памяти. Сериализация требует сначала преобразования объекта в бинарный байтовый поток, а затем десериализацию повторного укопирования бинарного байтового потока в кусок памяти объекта, что является относительно медленным.
3. Самый быстрый анализ исходного кода клонирования библиотеки библиотеки
В исходном коде основная логика обработки находится в классе клонера.
Есть две рекурсивные ссылки:
В (1) FastClone завершает объекты, унаследованные от класса интерфейса ifastclone, то есть все они являются копиями операций сбора;
В (2) CloneObject завершает процесс получения каждого свойства нормального объекта через механизм отражения, а затем присвоение значений для свойств недавно сгенерированного объекта с использованием objenesis.
Этот метод очень расширяется. Мало того, что вы можете полагаться на существующий код, чтобы завершить глубокое копирование, но и определить некоторые методы и типы клонирования, которые не требуют клонирования, что очень гибко.
4. Сравнение скоростей нескольких методов копирования
Приведенные выше три режима могут быть использованы для завершения глубокого копирования, и самый быстрый метод копирования - это то, о чем мы заботимся.
Во -первых, проверьте код:
public void testClonecomplex () бросает клоненотсупорноэкспрессии {final int copycount = 1; Список <sklexdo> SpeakTydolist = new ArrayList <sklexdo> (CopyCount * 3); Final Complexdo Complex = new Complexdo (); // Расчет двухсторонней библиотеки Long Start = System.currentTimeMillis (); for (int i = 0; i <copycount; ++ i) {final complexdo deepClone = clner.deepclone (комплекс); ComplexDolist.Add (DeepClone); } long End = System.currentTimeMillis (); System.out.println ("DeepClone Time =" + (End-Start)); // Вызов функции клона, реализованной клонируемым интерфейсом start = System.currentTimeMillis (); for (int i = 0; i <copycount; ++ i) {final Complexdo Interfaceclone = (комплекс) комплекс.clone (); ComplexDolist.Add (Interfaceclone); } end = System.CurrentTimeMillis (); System.out.println ("Interfaceclone Sost Time =" + (End-Start)); // сериализация и десериализация генерируют новый объект start = system.currenttimemillis (); for (int i = 0; i <copycount; ++ i) {final complexdo seirclone = seircopy (комплекс); ComplexDolist.Add (Seirclone); } end = System.CurrentTimeMillis (); System.out.println ("Стоимость Seirclone Time =" + (конечная группа)); }Единица результатов прогона составляет миллисекунды (эти данные игнорируются и не рассчитывают горячие точки Java и возможные GC).
Из этой таблицы мы можем сделать вывод:
1. Копирование клонируемого интерфейса является самым быстрым, потому что он включает в себя копии памяти, но если вовлеченные атрибуты являются более распространенными объектами, это немного трудно писать.
2. Копия сериализации/десериализации является самой медленной
3. Используя библиотеку клонирования, копирование механизма рекурсии и отражения медленнее, чем реализация клонируемого интерфейса, но быстрее, чем метод сериализации.
Выше приведено в этой статье, я надеюсь, что это будет полезно для каждого обучения.