概念
原型模式 : Prototype Pattern : 是一种创建型设计模式。
作用 : 通过复制现有的对象来创建新对象,无需通过new 来实例化新对象,从而达到简化对象创建的效果。
原型 : prototype : 定义用于复制自身以生成新对象的方法。通常 称为
clone()
【Object 类中,提供了一个 clone() 方法,该方法可以将一个Java对象复制一份,但是需要实现
Cloneable
接口】
具体原型 :ConcretePrototype : 实现了 原型接口的具体的类,对clone()
进行了具体的实现。
客户端 : Client : 使用具体原型对象来克隆新对象的应用程序代码。
拷贝的方式
浅拷贝
【定义】 :
1、浅拷贝是指创建一个新对象,然后将当前对象的非静态字段复制到该新对象。
2、如果字段是基本数据类型,则直接复制其值;但如果字段是引用类型,则复制的是引用地址,而不是引用的对象本身。
3、这意味着原始对象和副本对象中的引用类型字段将指向内存中的同一个对象。
【特点】 :
1、基本数据类型的字段被直接复制。
2、引用类型的字段只复制了引用,并没有复制引用的对象。
3、原始对象与副本对象共享引用类型的成员变量所指向的对象,任何一方对这些共享对象的修改都会影响另一方。
深拷贝
【定义】:
1、深拷贝不仅会创建一个新的对象,还会递归地复制所有引用类型字段指向的对象。
2、这意味着原始对象和副本对象的所有字段,包括基本数据类型和引用类型,都是完全独立的。
【特点】:
1、基本数据类型的字段同样被直接复制。
2、引用类型的字段也会被复制,不仅仅是引用地址,还包括引用的对象本身也被复制了一份。
3、原始对象与副本对象之间没有共享的对象,因此对任何一个对象的修改都不会影响另一个对象。
案例
主要是看
clone()
方法。
浅拷贝
原型类
java
// 实现 Cloneable 接口
public class Student implements Cloneable {
private String name;
private int age;
构造方法
getter
setter
toString
// 核心 : clone 方法
@Override
protected Object clone() throws CloneNotSupportedException {
// 简单的 浅拷贝
return super.clone();
}
}
测试代码
java
public class PrototyoeTest {
public static void main(String[] args) throws CloneNotSupportedException {
Student s1 = new Student("张三", 18);
Student s2 = (Student) s1.clone();
Student s3 = (Student) s1.clone();
System.out.println("s1 : "+s1 + " - "+s1.hashCode());
System.out.println("s2 : "+s2 + " - "+s2.hashCode());
System.out.println("s3 : "+s3 + " - "+s3.hashCode());
}
}
运行结果 :
s1 : Student{name='张三', age=18} - 931919113
s2 : Student{name='张三', age=18} - 1531448569
s3 : Student{name='张三', age=18} - 1867083167
深拷贝
方式一:直接手动写一下
java
public class School implements Cloneable {
private String name;
private String address;
构造方法
getter
setter
toString
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
java
public class Student implements Cloneable {
private String name;
private int age;
private School school; // 一个引用对象,深拷贝也会被拷贝
构造方法
getter
setter
toString
@Override
protected Object clone() throws CloneNotSupportedException {
// 深拷贝-手动进行引用对象的
Student cloneObj = (Student) super.clone();
// 手动的将引用的对象获取出来,重新赋值
School cloneSchool = (School) this.getSchool().clone();
cloneObj.setSchool(cloneSchool);
return cloneObj;
}
}
方式二:流式操作 - 推荐使用
涉及到 流式操作,需要进行序列化及反序列化,因此也会用到
Serializable
接口。
java
public class School implements Serializable {
private String name;
private String address;
构造方法
getter
setter
toString
}
java
public class Student implements Cloneable, Serializable {
private String name;
private int age;
private School school;
构造方法
getter
setter
toString
@Override
protected Object clone() throws CloneNotSupportedException {
// 深拷贝-使用流的方式进行对象的拷贝
/**
* 流程:
* 1、将对象转换成字节数组,写入 字节输出流中
* 2、从字节输入流中读取字节,再转换成对象,返回
*/
ByteArrayInputStream bis = null;
ByteArrayOutputStream bos = null;
ObjectInputStream ois = null;
ObjectOutputStream oos = null;
try{
bos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(bos);
oos.writeObject(this); // 将对象写入到字节输出流中
bis = new ByteArrayInputStream(bos.toByteArray());
ois = new ObjectInputStream(bis);
return ois.readObject(); // 从字节输入流中读取对象
}catch (Exception e){
e.printStackTrace();
}finally {
try{
if (bis != null){
bis.close();
}
if (bos != null){
bos.close();
}
if (ois != null){
ois.close();
}
if (oos != null){
oos.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
return null;
}
}
测试类
java
public class PrototyoeTest {
public static void main(String[] args) throws CloneNotSupportedException {
Student s1 = new Student("张三", 18);
s1.setSchool(new School("清华大学", "北京"));
Student s2 = (Student) s1.clone();
Student s3 = (Student) s1.clone();
System.out.println("s1 : "+s1 + " - "+s1.hashCode() + " - "+s1.getSchool().hashCode());
System.out.println("s2 : "+s2 + " - "+s2.hashCode() + " - "+s2.getSchool().hashCode());
System.out.println("s3 : "+s3 + " - "+s3.hashCode() + " - "+s3.getSchool().hashCode());
}
}
s1 : Student{name='张三', age=18, school=School{name='清华大学', address='北京'}} - 1607521710 - 764977973
s2 : Student{name='张三', age=18, school=School{name='清华大学', address='北京'}} - 500977346 - 20132171
s3 : Student{name='张三', age=18, school=School{name='清华大学', address='北京'}} - 186370029 - 2094548358