一、原型模式 知识回顾
原型模式定义: 用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象。
优点;
- Java 的原型模式是基于内存二进制流数据的复制,在性能上比 new 一个新对象更高
- 深克隆可保存对象的状态,简化了创建对象的过程
缺点:
- 需要为每一个类都配置 clone 方法
- clone 方法位于类的内部,当对已知的类修改时,需修改代码,违背了开闭原则
主要组成:
- 抽象原型类,规定了具体原型对象必须实现的接口
- 具体原型类,实现抽象原型类的 clone 方法,是可被复制的对象
- 访问类,使用具体原型类中的 clone 方法来复制新的对象
分类: 浅克隆 和 深克隆 两种
- 浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,但是对于非基本类型的属性(比如int、float、User 等),仍指向原有属性指向的对象的内存地址
- 深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原来的对象地址
Java 中的 Object 类提供了浅克隆到 clone 方法,具体原型类只要实现 cloneable 接口就可以实现对象的浅克隆。
模板代码:
浅拷贝:直接用等号赋值
public class Demo{
public static void main(String[] args) {
Object a = new Object();
Object b = a; // 浅克隆
System.out.println(a == b); // 输出结果为 true
}
}
深拷贝:实现 Cloneable 接口,重写 clone 方法,对于非基本类型的属性需要重新new对象,
Java 自带的 clone 方法实际上是一种浅克隆,只会克隆外层的对象,其内部的对象还是需要手动 new 的
class User implements Cloneable{
String name;
public User(String name) {
this.name = name;}
public String getName() {
return name;
}
@Override
protected User clone() throws CloneNotSupportedException {
User user = (User) super.clone();
user.name = new String(name);
return user;
}
}
public class Demo{
public static void main(String[] args) throws CloneNotSupportedException {
User uni1 = new User("uni");
User uni2 = uni1.clone();
System.out.println(uni1 == uni2); // false
System.out.println(uni1.getName() == uni2.getName()); // false
}
}
应用场景:
- 对象之间相同或者相似,只有部分几个属性不同
- 创建对象的成本较大,比如初始化时间长,占用 CPU 太多,或占用网络资源太多等
- 创建一个对象需要繁琐的数据准备或访问权限等,需提高性能或提高安全性
二、深克隆 与 浅克隆
在 JDK 8 源码中, Clonable 是一个从JDK1.0 出现的没有任何声明方法的空接口,源码如下:
package java.lang;
public interface Cloneable {
}
Java 提供 Cloneable 接口的作用:在运行时通知 JVM 可以安全地在该类上使用 clone () 方法,而如果该类没有实现 Clonebale 接口,那么调用 clone 方法则会抛出 CloneNotSupportedException 异常
使用 clone 方法需满足的条件:
- 【必选】克隆对象与原型对象不是同一个对象,即对任何对象 o,都有 o.clone() != o
- 【必选】克隆对象与原型对象的类型一样,即对任何对象 o, 都有 o.clone().getClass() == o.getClass()
- 【可选】对象 o 的 equals () 方法应当满足
o.clone().equals(o) == true
恒成立
基于之前的例子,我们定义了支持深克隆的 User对象,代码如下:
class User implements Cloneable{
String name;
public User(String name) {
this.name = name;}
pu