Java 中 Object 类是所有类的根类,Object 提供一个 clone() 方法,该方法可以将一个 Java 对象复制一份,但是需要实现 clone 的 Java 类必须要实现一个接口 Cloneable,该接口表示该类能够复制且具有复制的能力 =》 原型模式。
原型模式的注意事项和细节
- 创建新的对象比较复杂时,可以利用原型模式简化对象的创建过程,同时也可以提高效率;
- 不用重新初始化对象,而是动态的获得对象运行时的状态;
- 如果原始对象发生变化(增加或减少属性),其他克隆对象也会发生相应的变化,无需求该代码
- 缺点:需要为每一个类配备一个克隆方法,这对全新的类来说不是很难,但对已有的类进行改造时,需要修改其源代码,违背了 ocp 原则。
Sheep 重写 clone.
public class Sheep implements Cloneable{private String name;private int age;private String color;public Sheep() {}public Sheep(String name, int age, String color) {this.name = name;this.age = age;this.color = color;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getColor() {return color;}public void setColor(String color) {this.color = color;}@Overridepublic String toString() {return "Sheep{" +"name='" + name + '\'' +", age=" + age +", color='" + color + '\'' +'}';}// 使用默认的 clone 方法// 深拷贝@Overrideprotected Object clone(){Sheep sheep = null;try {sheep = (Sheep) super.clone();} catch (CloneNotSupportedException e) {e.printStackTrace();}return sheep;}}
两个对象属性是一样的,但是 hashCode 不相等。
public class Client {
public static void main(String[] args) {
Sheep sheep = new Sheep("tom", 1, "白色");
Sheep sheep1 = (Sheep) sheep.clone();
System.out.println(sheep1);
System.out.println(sheep.hashCode());
System.out.println(sheep1.hashCode());
}
}
深拷贝 & 浅拷贝
将上面那个例子改一下
public class Sheep implements Cloneable{
private String name;
private int age;
private String color;
private Sheep friend;
public Sheep() {
}
public Sheep(String name, int age, String color) {
this.name = name;
this.age = age;
this.color = color;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public Sheep getFriend() {
return friend;
}
public void setFriend(Sheep friend) {
this.friend = friend;
}
@Override
public String toString() {
return "Sheep{" +
"name='" + name + '\'' +
", age=" + age +
", color='" + color + '\'' +
", friend=" + friend +
'}';
}
// 使用默认的 clone 方法
// 深复制
@Override
protected Object clone(){
Sheep sheep = null;
try {
sheep = (Sheep) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return sheep;
}
}
public class Client {
public static void main(String[] args) {
Sheep sheep = new Sheep("tom", 1, "白色");
sheep.setFriend(new Sheep("jack", 2, "黑色"));
Sheep sheep1 = (Sheep) sheep.clone();
Sheep sheep2 = (Sheep) sheep.clone();
System.out.println("sheep1 " + sheep1.hashCode() + " sheep1.friend " + sheep1.getFriend().hashCode());
System.out.println("sheep2 " + sheep2.hashCode() + " sheep2.friend " + sheep2.getFriend().hashCode());
}
}
输出:
sheep1 1627674070 sheep1.friend 1360875712
sheep2 1625635731 sheep2.friend 1360875712
总结: 这边的 friend 只是浅拷贝,将内存地址指向第一个 sheep 对象。重写 clone 方法会深拷贝,重新生成一个对象,重新开辟一块内存空间。
深拷贝 - 序列化反序列化实现
// 深拷贝2
public Object deepClone() {
ByteArrayOutputStream bos = null;
ObjectOutputStream oos = null;
ByteArrayInputStream bis = null;
ObjectInputStream ois = null;
try {
// 序列化
bos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(bos);
oos.writeObject(this); //当前这个对象以对象流的方式输出
// 反序列化
bis = new ByteArrayInputStream(bos.toByteArray());
ois = new ObjectInputStream(bis);
DeepProtoType deepProtoType = (DeepProtoType) ois.readObject();
return deepProtoType;
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
try {
bos.close();
oos.close();
bis.close();
ois.close();
}catch (Exception ex){
ex.printStackTrace();
}
}
}
