Предисловие
Java Cloning (клон) является одной из особенностей языка Java, но его редко используют его на практике. Но иногда клонирование более удобно и эффективно.
Для клонов у Java есть некоторые ограничения:
1. Клонированный класс должен реализовать сам клонируемый интерфейс, чтобы указать, что метод Object.clone() может законно копировать экземпляр этого класса по поле. Клонируемый интерфейс на самом деле является интерфейсом идентификации и не имеет метода интерфейса.
2. Классы, которые реализуют клонируемый интерфейс, должны переопределить Object.clone (он защищен) с использованием публичных методов. Для объекта невозможно клонировать его после реализации этого интерфейса. Даже если метод клона называется отражательно, нет никакой гарантии, что он будет успешным.
3. Метод клонирования в классе Java.lang.Object определяется следующим образом:
защищенный объект клон () бросает клоненотсупорт
Создает и возвращает копию этого объекта. Это указывает на то, что это защищенный метод, видимый в том же упаковке.
По соглашению, возвращаемый объект должен быть получен путем вызова super.clone .
Назначение на Java
В Java задание очень часто используется, простое задание выглядит следующим образом
// исходный тип int a = 1; int b = a; // Справочный тип строки [] Weekdays = new String [5]; String [] gongzuori = Weekdays; // Списки только ссылки
В приведенном выше коде.
1. Если это исходный тип данных, значение, передаваемое назначением, является реальным значением.
2. Если это ссылочный тип данных, назначение передает ссылку на объект, а не на объект.
Понимание разницы между типами данных и эталонными типами облегчает нам понять клон.
Клон
В Java клон - это процесс копирования существующего объекта в память другому объекту, который такой же, как и он. Клонирование в Java является доменной копией.
Если вы хотите поддерживать методы клонов в Java, вам нужно сначала реализовать клонируемый интерфейс
Клонируемый на самом деле немного странно. Это отличается от интерфейса, который мы часто используем. Он не содержит никаких методов внутри, это просто маркировочный интерфейс.
Исходный код выглядит следующим образом
общедоступный интерфейс клонируемый {}О клонировании, на что следует обратить внимание
1. Если вы хотите поддержать клон, вам нужно реализовать интерфейс клонируемого
2. Если метод клона не вызван к клонируемому интерфейсу, будет брошено клоненотсупорноэкспений.
Затем переписывайте метод клона и измените его на уровень общественного доступа
Статический класс ClonableImp реализует клонируемый {public int count; общественный ребенок; @Override public Object Clone () бросает ClonenotSupportedException {return super.clone (); }}Вызовите метод клона, чтобы скопировать объект
ClonableImp Imp1 = new ColonableImp (); Imp1.child = new Child ("andy"); try {Object obj = Imp1.clone (); ClonableImp IMP2 = (ClonableImp) OBJ; System.out.println ("main imp2.child.name =" + imp2.child.name);} catch (clonenotsupportedException e) {e.printstacktrace ();}Легкая копия
Клон, реализованный в приведенном выше коде, на самом деле является мелкой копией.
Что вы должны знать о мелкой копии
1. Используйте метод клона по умолчанию
2. Сделайте копию значения исходного поля данных
3. Только копирование ссылок для ссылок типов
4. Быстрое исполнение и высокая эффективность
5. Данные не могут быть разделены на 100%.
6. Если объект содержит только исходный домен данных или об неизменную домен объекта, рекомендуется использовать мелкую копию.
Что касается неспособности отделить данные, мы можем использовать этот код для его проверки.
ClonableImp Imp1 = new ColonableImp (); Imp1.child = new Child ("andy"); try {Object obj = Imp1.clone (); ClonableImp IMP2 = (ClonableImp) OBJ; Imp2.child.name = "bob"; System.out.println ("main ip1.child.name =" + imp1.child.name);} catch (clonenotsupportedException e) {e.printstacktrace ();} В приведенном выше коде мы использовали метод клона IMP1 для клона IMP2, затем модифицировал imp2.child.name to Bob, а затем напечатал imp1.child.name , чтобы получить результат.
Главный IMP1.Child.Name = BOB
Причина в том, что мелкая копия не достигает 100% разделения данных. IMP1 и IMP2 имеют один и тот же дочерний объект, поэтому одна модификация повлияет на другую.
Глубокая копия
Глубокая копия может решить проблему 100% разделения данных. Просто внесите некоторые изменения в приведенный выше код.
1. Ребенок реализует клонируемый интерфейс.
Общедоступный класс Child реализует клонируемые {public String name; public Child (String name) {this.name = name; } @Override public String toString () {return "Child [name =" + name + "]"; } @Override Protected Object Clone () бросает ClonenotSupportedException {return super.clone (); }}2. Перепишите метод клона и вызовите метод клона домена данных.
Статический класс ClonableImp реализует клонируемый {public int count; общественный ребенок; @Override public Object Clone () бросает ClonenotSupportedException {clonableImp obj = (clonableImp) super.clone (); obj.child = (ребенок) Child.clone (); вернуть OBJ; }} Когда мы снова изменяем imp2.child.name , это не повлияет на значение imp1.child.name , поскольку IMP1 и IMP2 имеют свои собственные дочерние объекты, поскольку данные на 100% изолированы.
Некоторые функции глубокой копии
1. Вам необходимо переопределить метод клона, не только вызывая метод родительского класса, но и вызов метода клона атрибута.
2. 100% разделение данных между исходным объектом и клонированным объектом достигается
3. Если у объекта есть атрибут типа ссылки, рекомендуется использовать Deep Copy.
4. Глубокая копия более трудоемкая и менее эффективна, чем мелкая копия
Зачем использовать клонирование
Это очень важно и общепринято: API должен предоставить сбор списков, но не хочет, чтобы модификация вызывающего абонента влияла на его собственные изменения, поэтому ему необходимо клонировать объект для достижения цели изоляции данных.
Следует избегать как можно больше
1. Обычно интерфейс реализован, чтобы показать, что класс может сделать для своих клиентов, в то время как клонируемый-просто интерфейс тегов, и он также изменяет поведение защищенного от ручной работы метода в SuperClass. Это чрезвычайно нетипичное использование интерфейса и не достойно подражания.
2. Джавадок Описание соглашения о методе клонов и его хрупкого метода клонов немного неоднозначно, следующим образом: Конвенция Java SE8
Метод клона создает и возвращает копию объекта. Точное значение копии зависит от класса объекта. Общее значение состоит в том, что для любого объекта x выражение
x.clone() != x 为true x.clone().getClass() == x.getClass() также возвращает true, но не требуется x.clone().equals(x) также возвращает true, но не обязательно, но не обязательна
Второе и третье выражения выше легко возвращают ложные. Следовательно, единственное, что может гарантировать постоянное истинное, это выражение One, то есть эти два объекта являются независимыми объектами.
3. Окончательный домен объекта переменной. В методе клонирования, если нам нужно скопировать окончательный домен объекта переменной, на самом деле невозможно компилировать и пройти из -за окончательных ограничений. Поэтому, чтобы реализовать клонирование, мы должны рассмотреть возможность отказа от окончательного ключевого слова Mutable Object Domain.
4. Безопасность потока Если вы решите использовать безопасные для потока классы для реализации клонируемого интерфейса, вам необходимо убедиться, что его метод клона синхронизирован. Метод Object.clone по умолчанию. Clone не синхронизирован.
В целом, метод клонов в Java на самом деле не идеален, поэтому рекомендуется избегать его использования как можно больше. Вот некоторые альтернативы.
Копировать конструкторы
Копирование объектов также может быть реализовано с использованием конструктора копирования.
1. Copy Constructor также является типом конструктора
2. Принимается только один параметр, тип параметра - текущий класс
3. Цель состоит в том, чтобы генерировать новый объект с теми же параметрами, что и
4. Преимущество конструктора копирования по сравнению с методом клона состоит в том, что он прост и легко реализовать.
Пример кода с использованием конструктора копирования
открытый класс автомобиль {колесное колесо; Производитель струн; Public Car (колесное колесо, производитель струн) {this.wheel = wheel; this.manufacturer = производитель; } // Копировать конструктор Public Car (Car Car) {this (car.wheel, car.manufacturer); } public Static Class Wheel {String Brand; }}Обратите внимание, что приведенный выше код реализован как мелкая копия. Если вы хотите внедрить глубокую копию, пожалуйста, обратитесь к следующему коду.
// Копировать Constructorpublic Car (Car Car) {Wheel Wheel = new Wheel (); wlee.brand = car.wheel.brand; this.wheel = колесо; this.manufacturer = car.manufacturer;}Для большего удобства мы также можем добавить статический метод в вышеупомянутый класс
Public Static Car NewInstance (автомобиль) {вернуть новый автомобиль (автомобиль);}Используйте сериализуемые для получения глубокой копии
Фактически, глубокая копия объектов может быть достигнута с использованием сериализации. Краткий код выглядит следующим образом
Общедоступный класс DeepCopyExample реализует Serializable {Private Static Long Long SerialVersionUID = 6098694917984051357L; общественный ребенок; public DeepCopyExample copy () {DeepCopyExample copy = null; try {bytearrayoutputstream baos = new BytearrayOutputStream (); ObjectOutputStream oos = new ObjectOutputStream (BAOS); OOS.WriteObject (это); BytearrayinputStream bais = new Bytearrayinputstream (baos.tobytearray ()); ObjectInputStream OIS = new ObjectInputStream (BAIS); COPY = (DeepCopyExample) OIS.ReadObject (); } catch (ioException e) {e.printstackTrace (); } catch (classnotfoundexception e) {e.printstacktrace (); } return Copy; }}Среди них ребенок должен реализовать сериализуемый интерфейс
Public Class Child реализует Serializable {Private Static Final Long SerialVersionuid = 6832122780722711261L; public String name = ""; public Child (String name) {this.name = name; } @Override public String toString () {return "Child [name =" + name + "]"; }}Используйте примеры и тестовый код
DeepCopyExample пример = new DeepCopyExample (); Пример. Child = новый ребенок («Пример»); DeepCopyExample copy = example.copy (); if (copy! = null) {copy.child.name = "copied"; System.out.println ("example.child =" + example.child + "; copy.child =" + copy.child);} // Результат вывода: example.child = kild [name = anvess]; copy.child = kild [name = copied]Судя по результатам выходных результатов, изменение дочернего значения объекта копирования не влияет на значение ребенка объекта примера, то есть использование сериализации для достижения глубокой копии объекта.
Суммировать
Выше всего содержимое клонирования в Java. Я надеюсь, что эта статья будет полезна всем, чтобы выучить Java.