
How to clone an object correctly?
There are three ways to clone an object in Java:
Now in order. The first method implies that you will use the mechanism of the so-called “surface cloning” and take care of cloning the field objects yourself. The method
From the example above, it can be seen that in the clone and the original the state of one of the fields changes simultaneously. The next way is to use the copy constructor:
The class describes a constructor that takes an object of the same class and initializes the fields of the new object with the values of its fields. The implementation of the field initialization should be completely taken care of by the class developer.
But both of the above methods are full of potential errors and essentially create a copy of the object. The most convenient and flexible way to clone is the serialization mechanism. It consists in storing the object in a stream of bytes with subsequent exhumation of it from there. For example, we invite the cat Vaska, he is waiting for a couple of experiments:
Not a single cat was injured as a result of the tests, we see that Vaska was saved to the stream from which the independent clone was then restored. If there is no special need to process fields during cloning of objects, then serialization is the most preferable option for these purposes.
- Overriding the clone () method and implementing the Cloneable () interface;
- Using the copy constructor;
- Use the serialization mechanism for cloning
Now in order. The first method implies that you will use the mechanism of the so-called “surface cloning” and take care of cloning the field objects yourself. The method
clone()
in the parent class Object is protected, so you need to override it with the declaration as public. It returns an instance of an object with copied primitive fields and links. And it turns out that the original and its clone link fields point to the same objects. The example below shows how the field of the original object and the clone changes simultaneously.public class CloneTest{
static class Person implements Cloneable{
String name;
int age;
Car car;
Person(Car car,int age,String name) {
this.car = car;
this.age = age;
this.name = name;
}
@Override
public String toString() {
return this.name+" {" +
"age=" + age +
", car=" + car +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
static class Car{
public String color;
Car(String color) {
this.color = color;
}
@Override
public String toString() {
return "{" +
"color car='" + color + '\'' +
'}';
}
}
public static void main(String[] args) throws CloneNotSupportedException {
Car car = new Car("Green");
Person person=new Person(car,25,"Mike");
Person clone = (Person) person.clone();
System.out.println(person);
System.out.println(clone);
clone.name=new String("Ivan");
clone.car.color="red";
System.out.println(person);
System.out.println(clone);
}
}
Вывод:
Mike {age=25, car={color car='Green'}}
Mike {age=25, car={color car='Green'}}
Mike {age=25, car={color car='red'}}
Ivan {age=25, car={color car='red'}}
From the example above, it can be seen that in the clone and the original the state of one of the fields changes simultaneously. The next way is to use the copy constructor:
public class Person {
private int age;
private String name;
public Person(int age, String name){
this.age=age;
this.name=name;
}
// конструктор копии
public Person(Person other) {
this(other.getAge(), other.getName());
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
public static void main(String[] args) {
Person original = new Person(18, "Grishka");
Person clone = new Person(original);
System.out.println(original);
System.out.println(clone);
}
}
Вывод:
Person{age=18, name='Grishka'}
Person{age=18, name='Grishka'}
The class describes a constructor that takes an object of the same class and initializes the fields of the new object with the values of its fields. The implementation of the field initialization should be completely taken care of by the class developer.
But both of the above methods are full of potential errors and essentially create a copy of the object. The most convenient and flexible way to clone is the serialization mechanism. It consists in storing the object in a stream of bytes with subsequent exhumation of it from there. For example, we invite the cat Vaska, he is waiting for a couple of experiments:
import java.io.*;
class Cat implements Serializable{
private String name;
private String color;
private int age;
public Cat(String name, String color, int age) {
this.name = name;
this.color = color;
this.age = age;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
@Override
public String toString() {
return "Cat{" +
"name='" + name + '\'' +
", color='" + color + '\'' +
", age=" + age +
'}';
}
}
public class BasketCats{
public static void main(String[] args) throws IOException, ClassNotFoundException {
Cat vaska = new Cat("Vaska","Gray",4);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream ous = new ObjectOutputStream(baos);
//сохраняем состояние кота Васьки в поток и закрываем его(поток)
ous.writeObject(vaska);
ous.close();
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
//создаём кота для опытов и инициализируем его состояние Васькиным
Cat cloneVaska = (Cat)ois.readObject();
System.out.println(vaska);
System.out.println(cloneVaska);
System.out.println("*********************************************");
cloneVaska.setColor("Black");
//Убеждаемся что у кота Васьки теперь есть клон, над которым можно ставить опыты без ущерба Василию
System.out.println(vaska);
System.out.println(cloneVaska);
}
}
Вывод:
Cat{name='Vaska', color='Gray', age=4}
Cat{name='Vaska', color='Gray', age=4}
*********************************************
Cat{name='Vaska', color='Gray', age=4}
Cat{name='Vaska', color='Black', age=4}
Not a single cat was injured as a result of the tests, we see that Vaska was saved to the stream from which the independent clone was then restored. If there is no special need to process fields during cloning of objects, then serialization is the most preferable option for these purposes.