Клонирование, я считаю, что все слышали об этом. Первая в мире клонированная овца, Долли, использует технологию ядерной трансплантации для развития новых людей в соматических клетках взрослых млекопитающих, что очень волшебно. На самом деле, существует также концепция клонирования в Java, то есть реализовать копирование объектов.
Эта статья попытается представить некоторые углубленные вопросы о клонировании на Java, надеясь помочь вам лучше понять клонирование.
Предположим, вы хотите скопировать простую переменную. Очень просто:
int apples = 5; int pearls = яблоки;
Не только тип Int, остальные семь примитивных типов данных (логический, чар, байт, короткий, плавающий, двойной. Long) также применимы к этому типу ситуации.
Но если вы скопируете объект, ситуация немного сложна.
Предположим, я новичок, я бы написал это:
Класс Студент {Private Int Number; public int getNumber () {return №; } public void setNumber (int number) {this.number = number; / stu1.setnumber (12345); Студент stu2 = stu1; System.out.println ("Студент 1:" + stu1.getnumber ()); System.out.println ("Студент 2:" + stu2.getnumber ()); }}результат:
Студент 1: 12345
Студент 2: 12345
Здесь мы настроили класс ученика, в котором есть только одно числовое поле.
Мы создаем новый экземпляр студента и назначаем значение экземпляру STU2. (Студент stu2 = stu1;)
Давайте посмотрим на результаты печати. Как новичок, я похлопал мою грудь и живот, но объект был скопирован таким образом.
Это действительно так?
Мы стараемся изменить поле числового экземпляра STU2, а затем распечатать результат и видим:
stu2.setnumber (54321); System.out.println ("Студент 1:" + stu1.getnumber ()); System.out.println ("Студент 2:" + stu2.getnumber ());результат:
Студент 1: 54321
Студент 2: 54321
Это странно. Почему студенческое число студентов 2 изменилось, а также число студентов 1 также изменилось?
Причина заключается в предложении (stu2 = stu1). Цель этого утверждения - назначить ссылку на STU1 STU2.
Таким образом, Stu1 и Stu2 указывают на тот же объект в куче памяти. Как показано на картинке:
Итак, как мы можем достичь копирования объекта?
Вы помните, как царь всех возрастов возражает? Он имеет 11 методов, и есть два защищенных метода, одним из которых является метод клона.
В Java все классы по умолчанию унаследованы от класса объектов в языковом пакете Java. Проверьте его исходный код. Вы можете скопировать src.zip в своем каталоге JDK в другое место и распаковывать его, и весь исходный код включен. Я обнаружил, что есть метод с защищенным клоном квалификатора Access ():
/*Создает и возвращает копию этого объекта. Точное значение «копии» может зависеть от класса объекта. Общее намерение состоит в том, что для любого объекта x выражение: 1) x.clone ()! бросает ClonenotSupportedException;
Если вы присмотритесь, это все еще нативный метод. Все знают, что нативные методы-это код, реализованный на языках, не связанных с Java, и предназначены для Call By Java-программ. Поскольку программы Java работают на виртуальных машинах JVM, невозможно получить доступ к базовым связанным с операционной системам, и они могут быть реализованы только языками, близкими к операционной системе.
Первое объявление гарантирует, что клонированный объект будет иметь отдельное распределение адреса памяти.
Второе объявление показывает, что исходные и клонированные объекты должны иметь одинаковый тип класса, но это не обязательно.
Третье утверждение показывает, что исходные и клонированные объекты должны использоваться в равной степени методом Equals (), но это не обязательно.
Поскольку родительский класс каждого класса является объектом, все они содержат метод клона (), но поскольку метод защищен, ни один из них не может быть доступен за пределами класса.
Чтобы скопировать объект, вам необходимо переопределить метод клона.
Почему клон?
Давайте сначала подумаем о вопросе, зачем вам клонировать объекты? Разве не нормально просто новый объект?
Ответ: клонированный объект может содержать некоторые модифицированные свойства, а свойства нового объекта по -прежнему являются значениями во время инициализации, поэтому, когда новый объект необходим для сохранения «состояния» текущего объекта, метод клона зависит от метода клона. Итак, разве я не нормально назначать временные свойства этого объекта моему новому объекту один за другим? Это нормально, но давайте сначала не будем говорить об этом. Во -вторых, через приведенный выше исходный код все обнаружили, что клон является собственным методом, который быстро и реализован внизу.
Позвольте мне напомнить вам, что наш общий объект A = новый объект (); объект B; b = a; Эта форма кода копирует ссылки, то есть адрес объекта в памяти, а объекты A и B по -прежнему указывают на тот же объект.
Объект, назначенный методом клона, существует независимо от исходного объекта.
Как реализовать клонирование
Позвольте мне сначала представить два разных метода клонирования: мелкий клонинг и глубокий клонирование.
На языке Java типы данных разделены на типы значений (основные типы данных) и ссылочные типы. Типы значений включают простые типы данных, такие как Int, Double, Byte, Boolean, Char и т. Д., И ссылочные типы включают в себя сложные типы, такие как классы, интерфейсы, массивы и т. Д. Два будут введены подробно ниже.
Общие шаги (мелкое клонирование):
1. Скопированный класс должен реализовать клонируемый интерфейс (если вы не реализуете его, при вызове метода клона будет выброшен ClonenotsupportedException при вызове метода клона). Этот интерфейс представляет собой интерфейс тега (без какого -либо метода)
2. Переопределить метод клона () и установить модификатор доступа для общественности. Вызовите метод super.clone () в методе, чтобы получить необходимый объект копирования. (родной является местным методом)
Ниже приводится модификация приведенного выше метода:
Класс Студент реализует клонируемый {private int Number; public int getNumber () {return №;} public void setNumber (int number) {this.number = number;}@переопределить общедоступный объект Clone () {Student stu = null; try {stu = (студент) Super.clone ();} catchportexception e) {e.print (); stu;}} public class test {public static void main (String args []) {Student Stu1 = new Student (); Stu1.setnumber (12345); студент Stu2 = (студент) stu1.clone (); System.out.println ("Студент1:" + stu1.getnumb stu2.getnumber ()); stu2.setnumber (54321); System.out.println ("Student1:" + stu1.getnumber ()); System.out.println ("Student2:" + stu2.getnumber ());}}результат:
Студент 1: 12345
Студент 2: 12345
Студент 1: 12345
Студент 2: 54321
Если вы не верите, что эти два объекта не один и тот же объект, то вы можете взглянуть на это предложение:
System.out.println (stu1 == stu2); // ЛОЖЬ
Приведенная выше копия называется мелким клонированием.
Есть также немного более сложная глубокая копия:
Давайте добавим класс адреса в класс учеников.
Адрес класса {частная строка add; public String getAdd () {return add;} public void setAdd (строка Add) {this.Add = add;}} класс Студент реализует клонируемый {private int number; propload addr; public getAddr () {return addr;} public void setAddr (адрес addr) {addr = addr; setNumber (int number) {this.number = number;}@переопределять открытый объект Clone () {Student stu = null; try {stu = (студент) super.clone ();} catch (clonenotsupportedexception e) {e.printstacktrace ();} return stu;}} class test {public void void (string args argis args argis args args (string args args args args (string args argis args (restrics adredr Ardrace. Address ();; addr.setadd ("Hangzhou City"); Student Stu1 = new Student (); Stu1.setnumber (123); stu1.setaddr (addr); студент stu2 = (студент) stu1.clone (); System.out.println ("Студент 1:" + stu1.getnumb stu1.getaddr (). getAdd ()); System.out.println ("Студент 2:" + stu2.getNumber () + ", добавить:" + stu2.getAddr (). getAdd ());}}результат:
Студент 1: 123, адрес: Ханчжоу Студент 2: 123, Адрес: Ханчжоу
На первый взгляд, проблем нет, это действительно так?
Мы стараемся изменить адрес экземпляра ADDR в основном методе.
addr.setadd ("район Xihu"); System.out.println ("Студент 1:" + stu1.getNumber () + ", добавить:" + stu1.getAddr (). GetAdd ()); System.out.println ("Студент 2:" + stu2.getnumber () + ", добавить:" + stu2.getaddr (). GetAdd ());результат:
Студент 1: 123, Адрес: Ханчжоу Студент 2: 123, Адрес: Ханчжоу Студент 1: 123, Адрес: Студент Сюйху.
Это странно, почему изменились адреса обоих студентов?
Причина в том, что мелкое копирование только копирует ссылку на переменную ADDR и на самом деле не открывает другой кусок пространства. После копирования значения верните ссылку на новый объект.
Таким образом, для достижения истинного копирования объектов, а не чисто копирования. Нам нужно скопировать адрес адреса и изменить метод клона. Полный код заключается в следующем:
пакет ABC; Адрес класса реализует клонируемый {частная строка Add; public String getAdd () {return add; } public void setAdd (String Add) {this.add = add; } @Override public Object Clone () {адрес addr = null; try {addr = (адрес) super.clone (); } catch (clonenotsupportedException e) {e.printstacktrace (); } вернуть addr; }} класс Студент реализует клонируемый {private int №; частный адрес addr; общедоступный адрес getAddr () {return addr; } public void setAddr (адрес addr) {this.addr = addr; } public int getNumber () {return №; } public void setNumber (int number) {this.number = number; } @Override public Object Clone () {Студент stu = null; try {stu = (студент) super.clone (); // мелкая копия} catch (clonenotsupportedException e) {e.printstacktrace (); } stu.addr = (адрес) addr.clone (); // Глубокая копия возврата stu; / addr.setadd ("Hangzhou City"); Студент STU1 = новый студент (); stu1.setnumber (123); stu1.setaddr (addr); Студент stu2 = (студент) stu1.clone (); System.out.println ("Студент 1:" + stu1.getnumber () + ", адрес:" + stu1.getaddr (). GetAdd ()); System.out.println ("Студент 2:" + stu2.getNumber () + ", адрес:" + stu2.getAddr (). GetAdd ()); addr.setadd ("район Xihu"); System.out.println ("Студент 1:" + stu1.getnumber () + ", адрес:" + stu1.getaddr (). GetAdd ()); addr.setadd ()); System.out.println ("Студент 2:" + stu2.getNumber () + ", адрес:" + stu2.getAddr (). GetAdd ()); }}результат:
Студент 1: 123, адрес: Ханчжоу Студент 2: 123, адрес: Ханчжоу Студент 1: 123, Адрес: Студент Сюйху Студент 2: 123, Адрес: Город Ханчжоу
Этот результат соответствует нашим идеям.
Наконец, мы можем взглянуть на один из классов в API, который реализует метод клона:
java.util.date:
/*** Верните копию этого объекта. */ public Object Clone () {date d = null; try {d = (date) super.clone (); if (cdate! = null) {d.cdate = (basecalendar.date) cdate.clone (); }} catch (clonenotsupportedException e) {} // не произойдет return d; }Эта категория на самом деле является глубокой копией.
Мелкий клонирование и глубокое клонирование
1. Неглубокое клонирование
В мелком клонировании, если переменная элемента объекта прототипа имеет тип значения, одна копия будет скопирована в клонированный объект; Если переменная элемента объекта прототипа имеет эталонный тип, адрес справочного объекта будет скопирован в клонированный объект, то есть переменную элемента объекта прототипа, а клонированный объект указывают на один и тот же адрес памяти.
Проще говоря, в мелком клонировании, когда объект копируется, копируется только переменная члена типа значения объекта, а объект члена опорного типа не копируется.
На языке Java мелкое клонирование может быть реализовано путем перезаписи метода клона () класса объекта.
2. Глубокий клонирование
В глубоком клонировании, независимо от того, является ли элементная переменная объекта прототипа типом значения или ссылочным типом, одна копия будет скопирована в клонированный объект. Глубокое клонирование также копирует все ссылки на объекты прототипа объекта к клонированному объекту.
Проще говоря, в глубоком клонировании, за исключением того, что сам объект копируется, все переменные -члены, содержащиеся в объекте, также будут скопированы.
На языке Java, если вам нужно реализовать глубокое клонирование, его можно реализовать путем перезаписи метода Clone () объектного класса, или он может быть реализован с помощью сериализации и т. Д.
(Если ссылочный тип содержит много эталонных типов, или класс внутреннего эталонного типа содержит типы эталон, будет очень хлопотно использовать метод клона. В настоящее время мы можем использовать сериализацию для реализации глубокого клонирования объекта.)
Сериализация - это процесс написания объектов в поток. Объект, записанный в потоку, является копией исходного объекта, а исходный объект все еще существует в памяти. Копия, реализованная сериализацией, может не только копировать сам объект, но и копировать объекты участника, которые он ссылается. Следовательно, сериализация объекта на поток, а затем прочитав его из потока, может быть достигнуто глубокое клонирование. Следует отметить, что класс объекта, который может реализовать сериализацию, должен реализовать сериализуемый интерфейс, в противном случае операция сериализации не может быть реализована.
Расширенный
Код клонируемого интерфейса и сериализуемого интерфейса, предоставленного языком Java, очень прост. Они оба пустые интерфейсы. Этот пустой интерфейс также называется идентификационным интерфейсом. Нет определения какого -либо метода в интерфейсе идентификации. Его функция состоит в том, чтобы сказать JRE, имеют ли классы реализации этих интерфейсов определенную функцию, например, поддерживают ли они клонирование, поддерживают ли они сериализацию и т. Д.
Решить многослойные проблемы клонирования
Если тип эталона содержит много типов эталон, или класс внутреннего эталонного типа содержит типы ссылок, будет очень трудно использовать метод клона. В настоящее время мы можем использовать сериализацию для реализации глубокого клонирования объекта.
открытый класс Внешний реализация Serializable {Private Static Final Long SerialVersionUID = 369285298572941L; // Лучше всего явно объявить об идентификационном внутреннем внутреннем внутреннем месте; // Описание: [Метод глубокой копии, требует сериализованного объекта и всех свойств объекта] Public Outter MyClone () {Внешний внешний = null; Попробуйте {// сериализовать объект в поток, потому что то, что записано в потоке, является копией объекта, а исходный объект все еще существует в JVM. Поэтому, используя эту функцию, вы можете получить глубокую копию объекта BytearRayoutputStream BAOS = New BytearRayOutputStream (); ObjectOutputStream oos = new ObjectOutputStream (BAOS); OOS.WriteObject (это); // сериализовать поток в объект BytearRayinptstream bais = new Bytearrayinputstream (baos.tobytearray ()); ObjectInputStream OIS = new ObjectInputStream (BAIS); внешний = (внешний) ois.readobject (); } catch (ioException e) {e.printstackTrace (); } catch (classnotfoundexception e) {e.printstacktrace (); } вернуть внешний; }}Внутренний должен также реализовать сериализуемые, в противном случае он не может быть сериализован:
Общедоступный класс внутренний реализует сериализуемые {частный статический конечный длинный сериал -версион = 872390113109L; // Лучше всего явно объявить идентификатор public String name = ""; public inner (string name) {this.name = name; } @Override public String toString () {return "Значение имени внутреннего:" + name; }}Это также может позволить двум объектам существовать полностью независимо в пространстве памяти, не влияя на значения друг друга.
Суммировать
Есть два способа реализации клонирования объекта:
1). Реализовать клонируемый интерфейс и переопределить метод Clone () в классе объекта;
2). Реализуйте сериализуемый интерфейс и реализуйте клонирование посредством сериализации объектов и десериализации, что может реализовать истинный глубокий клонирование.
Примечание. Клонирование, основанное на сериализации и десериализации, является не просто глубоким клонированием, но, что более важно, благодаря общему ограничению, можно проверить, поддерживает ли объект для клонирования сериализации. Эта проверка проводится компилятором и не бросает исключения во время выполнения. Это решение, очевидно, лучше, чем клонирование объектов, используя метод клона класса объекта. Всегда лучше оставить проблему для выполнения, разоблачив ее при компиляции.
Выше приведено подробное объяснение кода клонирования объекта программы Java программирования (копия), я надеюсь, что это будет полезно для всех. Заинтересованные друзья могут продолжать ссылаться на другие связанные темы на этом сайте. Если есть какие -либо недостатки, пожалуйста, оставьте сообщение, чтобы указать это.