一、一句话理解
用已有的对象做‘模子’,通过复制(克隆)快速产生新对象,而不用重新走构造函数,但要小心深浅拷贝这把双刃剑。
“ctrl+c / ctrl+v 生成对象”
二、生活中的例子
1、3D 打印:把原模型放进扫描仓,一键打印出同款。
2、复印证件:原件(原型)放上去,按复印键即可,不用重新去xx所办一张。三、Java 代码(两种复制路线)
1. 默认浅克隆 —— 实现 Cloneable 标记接口,重写 Object.clone()
public class Sheep implements Cloneable { // 多莉羊
private String name;
private int age;
private List<String> hobbies; // 引用类型——注意浅克隆问题
public Sheep(String name, int age, List<String> hobbies) {
this.name = name;
this.age = age;
this.hobbies = hobbies;
}
@Override
public Sheep clone() { // 改返回类型,方便调用
try {
return (Sheep) super.clone(); // 浅拷贝
} catch (CloneNotSupportedException e) {
throw new AssertionError(); // 不会发生
}
}
/* getter/setter 省略 */
}
客户端:
Sheep orig = new Sheep("Dolly", 3, Arrays.asList("eat", "sleep"));
Sheep copy = orig.clone(); // 0 成本 new
陷阱:hobbies 是同一个 List 对象,改 copy.getHobbies().add("sing") 会影响原羊。
2. 深克隆 —— 自己复制引用字段,或借助序列化/JSON
@Override
public Sheep clone() {
try {
Sheep s = (Sheep) super.clone();
s.hobbies = new ArrayList<>(this.hobbies); // 手动深拷贝
return s;
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
}
public <T extends Serializable> T deepClone() {
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos)) {
oos.writeObject(this);
try (ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis)) {
return (T) ois.readObject();
}
} catch (IOException | ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
四、标准角色
1、Prototype : 声明克隆方法的接口(Java 里通常是 Cloneable + clone())
2、ConcretePrototype : 实现克隆逻辑的具体类
3、Client : 持有原型实例,调用 clone() 获得新对象,无需 new
五、优缺点
优点
1、运行期动态复制,避开构造函数,性能更高(尤其大对象、复杂依赖)。
2、保护原始对象:克隆完随意改副本,不影响原型。
3、简化创建:当对象构建步骤巨多、参数巨多时,直接“抄作业”比建造者还香。
4、可配合注册表(Prototype Registry)实现“对象缓存池”——提前 clone 好模板,用的时候秒拿。
缺点
1、深/浅拷贝容易踩坑:引用类型必须手动深克隆,否则出现共享数据。
2、每个具体类都要实现克隆逻辑,代码散落。
3、循环引用对象图深克隆时会栈溢出,需要特殊处理。
4、Cloneable 接口设计被官方吐槽(Effective Java 第 13 条),建议用拷贝构造器 / 工厂方法 / 序列化代替。
六、和工厂系列、建造者的区别
维度 | 工厂/建造者 | 原型 |
创建方式 | 从零 new 或分步攒料 | 直接内存复制 |
是否走构造器 | 是 | 否 |
性能 | 对象大、初始化复杂时较慢 | 复制内存,快 |
适用场景 | 一般创建 | 构造开销大、对象图复杂、需要运行时副本 |
七、真实 JDK / 开源落地
1、java.lang.Object.clone() 与 java.lang.Cloneable
数组就是典型原型:int[] a2 = a1.clone();
2、java.util.ArrayList#clone()
集合自身支持浅克隆,元素不复制。
3、Spring BeanDefinition 的 scope="prototype"
容器每次 getBean 都调 clone() 返回新实例,与单例相反。
4、JSON 库 Gson.fromJson(json, Foo.class) 本质也是“先序列化再反序列化”完成深克隆。
游戏引擎(Unity、Cocos)里“节点复制”= 原型模式,一键生成敌方小兵。
八、使用场景口诀
“构造慢、对象大,副本多、要缓存;深拷贝、防共享,原型帮你秒克隆。”