用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型对象相同的新对象。
抽象原型类:规定了具体原型对象必须实现的clone()方法。JDK已经提供了java.lang.Cloneable抽象原型类。
具体原型:实现抽象原型类的clone()方法,它是被复制的对象。
访问类:使用具体原型类的clone()方法来复制新的对象。
浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,扔指向原有属性锁指向的对象的内存地址。如JDK中的Object提供的clone()方法。
深克隆:创建一个新对象,属性中应用的其他对象也会被克隆,不再指向原有对象的地址。
public class Object {
protected native Object clone() throws CloneNotSupportedException;
}
public interface Cloneable {
}
使用new关键字创建对象会调用构造方法,使用clone()方法克隆对象并不会调用构造方法。
@Data
@RequiredArgsConstructor
@AllArgsConstructor
public class Attribute {
private int age;
}
实现JDK自带的java.lang.Cloneable接口。
@Data
public class Sheep implements Cloneable {
private String name;
private Attribute attribute;
public Sheep() {
System.out.println("Sheep构造函数");
}
@Override
protected Sheep clone() throws CloneNotSupportedException {
System.out.println("开始克隆羊");
return (Sheep)super.clone();
}
}
public class Client {
public static void main(String[] args) throws Exception {
Attribute attribute = new Attribute(2);
Sheep prototype = new Sheep();
prototype.setName("原型羊");
prototype.setAttribute(attribute);
Sheep copy = prototype.clone();
copy.setName("多莉(Dolly)");
attribute.setAge(3);
// 原型羊:3
System.out.println(prototype.getName() +":"+prototype.getAttribute().getAge());
// 多莉(Dolly):3
System.out.println(copy.getName()+ ":" + copy.getAttribute().getAge());
}
}
java.lang.Cloneable#clone()方法就是浅拷贝,所以当拷贝对象的时候只是拷贝对象的内存地址,所以一旦修改原型中的引用对象的属性,那么拷贝出来的对象也会跟着改变。
注意事项:
public class Main {
public static void main(String[] args) {
Sheep prototype = new Sheep();
prototype.setName("原型羊");
prototype.setAttribute(new Attribute(2));
Sheep target = new Sheep();
BeanUtils.copyProperties(prototype, target);
target.getAttribute().setAge(3);
System.out.println(prototype.getName() +":"+prototype.getAttribute().getAge());
System.out.println(target.getName()+ ":" + target.getAttribute().getAge());
}
}
方案一:通过对象序列化实现(每个对象都要实现序列化接口Serializable)。
@Data
@RequiredArgsConstructor
@AllArgsConstructor
public class Attribute implements Serializable {
private int age;
}
@Data
public class Sheep implements Serializable {
private String name;
private Attribute attribute;
}
public class Client {
public static void main(String[] args) throws Exception {
Attribute attribute = new Attribute(2);
Sheep prototype = new Sheep();
prototype.setName("原型羊");
prototype.setAttribute(attribute);
// 对象序列化到文件
String file = "/Users/mengday/Downloads/oos.txt";
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file));
oos.writeObject(prototype);
oos.close();
// 序列化文件转对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
Sheep copy = (Sheep)ois.readObject();
copy.getAttribute().setAge(3);
// 原型羊:2
System.out.println(prototype.getName() +":"+prototype.getAttribute().getAge());
// 多莉(Dolly):3
System.out.println(copy.getName()+ ":" + copy.getAttribute().getAge());
}
}