Что такое клонирование как реализовано клонирование в java
Перейти к содержимому

Что такое клонирование как реализовано клонирование в java

  • автор:

Как реализовано глубокое клонирование в java

В Java глубокое клонирование можно реализовать двумя способами:

1 Реализовать интерфейс Cloneable и переопределить метод clone() .

При этом, необходимо скопировать все поля объекта и рекурсивно клонировать все объекты, которые содержатся в этом объекте.

public class MyClass implements Cloneable  private int x; private String str; private MyOtherClass obj; // constructors, getters, and setters @Override public Object clone() throws CloneNotSupportedException  MyClass cloned = (MyClass) super.clone(); cloned.obj = (MyOtherClass) obj.clone(); return cloned; > > public class MyOtherClass implements Cloneable  private int y; private String str2; // constructors, getters, and setters @Override public Object clone() throws CloneNotSupportedException  return super.clone(); > > 

2 Использовать механизм сериализации объектов.

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

public class MyClass implements Serializable  private int x; private String str; private MyOtherClass obj; // constructors, getters, and setters public MyClass deepCopy() throws IOException, ClassNotFoundException  ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(this); ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bais); return (MyClass) ois.readObject(); > > public class MyOtherClass implements Serializable  private int y; private String str2; // constructors, getters, and setters > 

Оба способа имеют свои преимущества и недостатки, но использование механизма сериализации может быть медленнее и менее эффективным, чем использование метода clone()

Клонирование Object’ов с модификатором final

Если в классе копируемого объекта все поля final — да клонируемый объект будет неизменяемый.

class Original impl Clonable < private final Object obj; Original(Object obj)< this.obj=obj; >Original clone()

данный объект неизменяемый (все поля final) при копировании возвращается новый неизменяемый объект

Если вы про клонирование объекта и будет ли переменная содержащая этот объект final, то все зависит от её объявления.

final Object clone = original.clone(); — переменная объекта final

Как работает метод клонирования Java?

Почему Java возвращает объект класса студента вместо возвращения объекта класса объекта. Поскольку мы используем super. Означает ли это, что сама Java обеспечивает поверхностное клонирование в методе клонирования?

Поделиться Источник 27 июля 2013 в 12:08

4 ответа

Клонирование в Java — это поле по копированию , т.е. если класс Object не имеет представления о структуре класса, на который будет вызван метод clone().

1) Если класс имеет только примитивные члены типа данных, то будет создана совершенно новая копия объекта, и ссылка на новую копию объекта будет возвращена.

2) Если класс содержит члены любого типа класса, то будут скопированы только ссылки на эти члены, и, следовательно, ссылки на члены как в исходном объекте, так и в клонированном объекте будут ссылаться на один и тот же объект.

Поделиться 27 июля 2013 в 12:14

Смотрите, что говорят об этом документы:

. Таким образом, этот метод выполняет «покрытую копию» этого объекта, а не операцию «глубокой копии».

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

Поделиться 27 июля 2013 в 12:14

Метод clone() действует как конструктор копирования.

Он создает и возвращает копию объекта. Поскольку класс Object имеет метод clone (защищенный), вы не можете использовать его во всех ваших классах. Класс, который вы хотите клонировать, должен реализовать метод клонирования и перезаписать его. Он должен предоставить свое собственное значение для копирования или, по крайней мере, вызывать super.clone() . Также вам нужно реализовать интерфейс маркера Cloneable, иначе вы получите CloneNotSupportedException. Когда вы вызываете метод super.clone() , то вы зависим от реализации класса Object, и то, что вы получаете, является мелкой копией.

Вы можете перейти на страницу Wiki для более подробного понимания.

Для клонирования объекта необходимо реализовать интерфейс Cloneable

Если вы пытаетесь использовать метод клонирования в классе, где не реализован интерфейс Cloneable , это выводит CloneNotSupportedException .

Поделиться 27 июля 2013 в 12:26

java.lang.Object предоставляет стандартную реализацию метода clone() в Java. Он объявлен как защищенный и нативный в классе Object , поэтому реализован в нативном коде. Поскольку его соглашение возвращает clone() объекта, вызывая метод super.clone() , любой процесс клонирования в конечном итоге достигает метода clone() java.lang.Object . Этот метод сначала проверяет, реализует ли соответствующий объект интерфейс Cloneable , который является интерфейсом маркера. Если этот экземпляр не реализует Cloneable, то в Java выкидывает CloneNotSupportedException , проверяемое исключение, которое всегда требуется обрабатывать при клонировании объекта. В Java, если класс нуждается в поддержке клонирования, он должен делать следующие вещи:

A) Вы должны реализовать интерфейс Cloneable . B) Вы должны переопределить метод clone() из класса Object . [Это странно. Метод clone() должен был находиться в интерфейсе Cloneable .]

Документы Java о методе clone() приведены ниже (отформатированы и извлечены). /* Создает и возвращает копию этого объекта. Точное значение «копировать» может зависеть от класса объекта. Общее намерение заключается в том, что для любого объекта x выражение: 1) x.clone()!= x будет истинным //гарантирует, что клонированный объект будет иметь отдельное присвоение адреса памяти. 2) x.clone().getClass() == x.getClass() будет истинным, но это не абсолютные требования.//оригинальные и клонированные объекты должны иметь одинаковый тип класса, но это не обязательно. 3) x.clone().equals(x) будет истинным, это не абсолютное требование.//оригинальные и клонированные объекты должны быть равными с помощью метода equals() , но это не обязательно. */

Давайте посмотрим на пример:

public class MyClone < int x; public static void main(String[] args) throws CloneNotSupportedException < MyClone c = new MyClone(); MyClone a = (MyClone) c.clone(); // Type-cast is required >> 

Поскольку clone() является частью класса Object , и Object не будет реализовывать интерфейс Cloneable , когда наш собственный класс не будет реализовывать интерфейс Cloneable , JVM не будет знать, что этот класс подходит для клонирования, поэтому выходит CloneNotSupportedException .

Есть только две вещи, которые возможны, когда мы говорим MyClone a = (MyClone) c.clone(); :

Либо он вернет клонированный объект.

Или это вызовет CloneNotSupportedException .

Поскольку ясно, что не обязательно реализовывать clone() в вашем классе, когда вы хотите клонировать объект, если вы не хотите, метод clone() в классе Object объявлен защищенным — только подклассы и члены одного пакета смогут вызывать clone() на объекте. Если вы хотите изменить это, вы должны переопределить его и сделать его общедоступным.

Проверяет перед вызовом метода clone() :

if(c instanceof Cloneable)

Примечание: Ни один конструктор не вызывается, когда вызывается clone() . Наша ответственность — правильно установить все переменные-члены этого класса.

Room.java public class Room < private String roomSize; public Room(String roomSize)< this.roomSize = roomSize; >//Any Getters-Setters go here > Flat.java public class Flat implements Cloneable < private String flatNumber; private Room room; public Flat(String size,Room room)< this.size = size; this.room = room; >public Object clone() < try < return (Flat)super.clone(); >catch (CloneNotSupportedException e) < System.out.println("CloneNotSupportedException comes out : " +e.getMessage()); >> //Any Getters-Setters go here > Main.java public class Main < public static void main(String[] args) < Room room = new Room("40 X 40"); Flat flat1 = new Flat(403 , room); Flat flat2 = (Flat)flat1.clone(); >> 

Здесь super.clone() вызывается внутри clone() . Как мы знаем, clone() объявлен в Object , поэтому он наследуется каждым объектом Java. Вызов super.clone() копирует поля нашего суперкласса и делает побитовые копии полей. Это известно как shallow copy, что означает, что при копировании Flat с помощью clone() , flatNumber поля копируется с соответствующими значениями, но пространство копируется по ссылке — побитовое копирование, адрес памяти копируется.

Любые изменения, которые вы вносите в пространство исходного объекта, будут отражены в клонированном объекте и наоборот. Для решения этой проблемы нам нужна глубокая копия. Теперь нам нужно изменить класс Room , а также реализовать интерфейс Cloneable и метод clone() , затем вызвать метод clone() объекта Room внутри метода clone() объекта Flat .

Room.java public class Room < private String roomSize; public Room(String roomSize)< this.roomSize = roomSize; >public Object clone() < try < return (Room)super.clone(); >catch (CloneNotSupportedException e) < System.out.println("CloneNotSupportedException comes out : " +e.getMessage()); >> //Any Getters-Setters go here > Flat.java public class Flat implements Cloneable < private String flatNumber; private Room room; public Flat(String size,Room room)< this.size = size; this.room = room; >public Object clone() < Flat flat = null; try < flat = (Flat)super.clone(); >catch (CloneNotSupportedException e) < System.out.println("CloneNotSupportedException comes out : " +e.getMessage()); >flat.room = (Room) room.clone(); return flat; > //Any Getters-Setters go here > Main.java public class Main < public static void main(String[] args) < Room room = new Room("40 X 40"); Flat flat1 = new Flat(403, room); Flat flat2 = (Flat)flat1.clone(); >> 

Надеюсь, это даст лучшее понимание клонирования и его реализации.

Клонирование

Java-университет

Доброго времени суток. В доп. материалах к 21 уровню прочитал, что, если хочешь пользоваться реализацией клонирования по умолчанию (той, что есть у класса Object), то нужно реализовать интерфейс Cloneable и переопределить метод clone(), вызвав в нём метод clone() класса предка. Это я понял, усвоил, запомнил: вобщем или реализовывай clone() с нуля, не обращаясь к методу clone() суперкласса (тогда и маркернрый интерфейс Cloneable по сути не нужно реализовывать в своём классе) или делай то, о чем я написал ранее. Усвоено. У меня нет понимания почему нельзя просто реализовать интерфейс Cloneble без переопределения метода clone(), если я хочу реализацией по умолчанию воспользоваться. Лезу к класс Object, вижу у метода clone() модификатор protected, понимаю, что этот метод должен быть доступен всем наследникам, коими являются все классы. Но компилятор ругается на попытку вызвать метод clone() без его переопределения в моём классе. Думаю, ну наверное нужно явное наследование может быть, добавляю к своему классу extands Object (оставив разумеется implements Cloneable), но компилятор все равно ругается на попутку вызвать clone() без его переопределения в моём классе. Ну, то есть я понял как надо клонировать правильно, но я хочу докопаться и понять, как компилятор понимает, что нельзя воспользовать реализацией по умолчанию, не переопределив её в своём классе. Ну вот на такой простой пример компилятор ругается в месте вызова метода clone()
public class CloneTesting < public static class Cat extends Object implements Cloneable < String name; public Cat(String name) < this.name = name; >//@Override //public Cat clone() throws CloneNotSupportedException < // return (Cat) super.clone(); //>> public static void main(String[] args) throws CloneNotSupportedException < Cat cat1 = new Cat("Пуля"); //вариант клонирования по умолчанию. Object cat2 = cat1.clone(); System.out.println(cat1); System.out.println(cat2); >>

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *