声明:此笔记为B站up主“程序员大表哥”所授课程【23种java设计模式】个人学习笔记,仅供学习,不做他用。
链接:https://www.bilibili.com/video/av81810102
知识点:
1.Cloneable接口/Object#clone方法详解
2.浅拷贝/深拷贝
3.序列化机制实现深拷贝
模式定义:
指原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
应用场景:
当代码不应该依赖于需要复制的对象的具体类时请使用Prototype模式。
优点:
1.可以不耦合具体类的情况下克隆对象
2.避免重复的初始化代码
3.更方便的构建复杂对象
Spring源码中的应用
1 org.springframework.beans.factory.support .AbstractBeanDefinition
2 java.util.Arrays
1.Cloneable接口/Object#clone方法详解
继承Cloneable接口,并重写clone()方法:
class BaseInfo implements Cloneable{
private String companyName;
@Override
protected BaseInfo clone() throws CloneNotSupportedException {
return ((BaseInfo) super.clone());
}
2.浅拷贝/深拷贝
8种基本数据类型:Java中有8种基本数据类型(小写开头)boolean、byte、short、char、int、float、long、double,基本数据类型作为Java语言的一部分,但基本数据类型不是对象,基本数据类型放在堆栈中,对象放在堆中。Java针对每种基本数据类型提供了包装类(大写开头),即Boolean、Byte等。这样就解决了基本数据类型面向对象用的问题。
不可变类:是实例创建后就不可以改变成员变量的值。这种特性使得不可变类提供了线程安全的特性但同时也带来了对象创建的开销,每更改一个属性都是重新创建一个新的对象。JDK内部也提供了很多不可变类如Integer、Double、String等。String的不可变特性主要为了满足常量池、线程安全、类加载的需求。合理使用不可变类可以带来极大的好处。
可变类: 当你获得这个类的一个实例引用时,你可以改变这个实例的内容。
**举个例子:**String和StringBuffer,String是immutable的,每次对于String对象的修改都将产生一个新的String对象,而原来的对象保持不变,而StringBuffer是mutable,因为每次对于它的对象的修改都作用于该对象本身,并没有产生新的对象。
浅拷贝:如果拷贝对象所有类型为不可变类型,则浅拷贝即可:
class BaseInfo implements Cloneable{
private String companyName;
@Override
protected BaseInfo clone() throws CloneNotSupportedException {
return ((BaseInfo) super.clone());
}
深拷贝:如果拷贝对象有可变类型,则需要深拷贝:
class Product implements Cloneable{
private String part1;
private String part2;
private Integer part3;
private Integer part4;
private BaseInfo baseInfo;
@Override
protected Product clone() throws CloneNotSupportedException {
Product clone= ((Product) super.clone());
//对BaseInfo的深拷贝
BaseInfo clone1=this.baseInfo.clone();
clone.setBaseInfo(clone1);
return clone;
}
}
3.序列化机制实现深拷贝
一般不建议序列化实现,开销大
Product类以及Product类包含的BaseInfo类必须实现Serializable接口:
protected Product clone() {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
try (ObjectOutputStream oos = new ObjectOutputStream(byteArrayOutputStream);) {
oos.writeObject(this);
} catch (IOException e) {
e.printStackTrace();
}
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
try (ObjectInputStream ois = new ObjectInputStream(byteArrayInputStream)) {
Product object = ((Product) ois.readObject());
return object;
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}