Java设计模式之原型模式

本文详细介绍了Java中的原型模式,区分浅拷贝与深拷贝,并通过实例展示了如何在ConcretePrototype中实现浅克隆和深克隆,帮助读者理解克隆对象的原理及其实现方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原型模式

Prototypye

简介

原型模式

类似复制粘贴功能

创建一个实例,用这个实例去拷贝创建新实例(直接从内存中拷贝)

角色
  • 抽象原型(Prototype)
    • 核心:需要实现Cloneable接口,重写clone方法
    • 说明这个类能够被克隆复制的功能
  • 具体原型(Concrete Prototype)
    • 实现抽象原型类
  • 客户端(Cline)
    • 提出创建对象请求(用户使用复制粘贴)

大话设计模式中的图片

在这里插入图片描述

分类

浅拷贝(浅克隆)

基本类型拷贝是值传递,引用类型拷贝的是同一个内存地址

改变原对象的引用类型字段时,副本对象的该字段也会被修改

注意: 如果改变的是String类型,虽然它是引用类型,但String不可变,它实际上并不是在原有的内存地址上改动,而是给原对象String字段换了一块内存地址,所以副本对象该字段不会变

浅克隆代码

public class Prototype implements Cloneable {
    private String fileName;
    private Integer fileId;
    private Date time;

    @Override
    protected Object clone() throws CloneNotSupportedException {
       return super.clone();//核心
    }

    public Prototype(String fileName, Integer fileId, Date time) {
        this.fileName = fileName;
        this.fileId = fileId;
        this.time = time;
    }

    // get/set方法
}
public class ConcretePrototype extends Prototype {
    public ConcretePrototype(String fileName, Integer fileId, Date time) {
        super(fileName, fileId, time);
        System.out.println("执行构造方法============================================");
    }

    public void show(){
        System.out.println("文件名:"+this.getFileName());
        System.out.println("文件id:"+this.getFileId());
        System.out.println("时间:"+this.getTime());
    }
}
public class Cline {
    public static void main(String[] args) throws CloneNotSupportedException {
        Date date = new Date();
        ConcretePrototype concretePrototype = new ConcretePrototype("学生信息文件", 0, date);
        ConcretePrototype cloneA = (ConcretePrototype) concretePrototype.clone();
        ConcretePrototype cloneB = (ConcretePrototype) concretePrototype.clone();

        System.out.println(concretePrototype.hashCode());
        System.out.println(cloneA.hashCode());
        System.out.println(cloneB.hashCode());
        System.out.println("===========================");
        concretePrototype.show();
        cloneA.show();
        cloneB.show();

        System.out.println("==============================");

        date.setTime(999999999);
        concretePrototype.show();
        cloneA.show();
        cloneB.show();
    }
}
/*
执行构造方法============================================
356573597
1735600054
21685669
===========================
文件名:学生信息文件
文件id:0
时间:Sat May 16 10:59:11 CST 2020
文件名:学生信息文件
文件id:0
时间:Sat May 16 10:59:11 CST 2020
文件名:学生信息文件
文件id:0
时间:Sat May 16 10:59:11 CST 2020
==============================
文件名:学生信息文件
文件id:0
时间:Mon Jan 12 21:46:39 CST 1970
文件名:学生信息文件
文件id:0
时间:Mon Jan 12 21:46:39 CST 1970
文件名:学生信息文件
文件id:0
时间:Mon Jan 12 21:46:39 CST 1970
*/

在这里插入图片描述

修改concretePrototype的属性time,cloneA和cloneB的属性一同被修改了(图中date为time)

深拷贝(深克隆)

基本类型拷贝是值传递,引用类型拷贝是开辟另一块内存地址,将原数据拷贝到新内存地址上

改变原对象的引用字段不会对副本对象的该字段有影响

深克隆代码

public class Prototype implements Cloneable {
    private String fileName;
    private Integer fileId;
    private Date time;

    @Override
    protected Prototype clone() throws CloneNotSupportedException {
        Object object = super.clone();

        Prototype v = (Prototype) object;
        v.time = (Date) this.time.clone();//将属性time格外克隆出来
        return v;
    }

    public Prototype(String fileName, Integer fileId, Date time) {
        this.fileName = fileName;
        this.fileId = fileId;
        this.time = time;
    }
    // get/set/构造方法...
}
public class ConcretePrototype extends Prototype {
    public ConcretePrototype(String fileName, Integer fileId, Date time) {
        super(fileName, fileId, time);
        System.out.println("执行构造方法");
    }

    public void show(){
        System.out.println("文件名:"+this.getFileName());
        System.out.println("文件id:"+this.getFileId());
        System.out.println("时间:"+this.getTime());
    }
}
public class Cline {
    public static void main(String[] args) throws CloneNotSupportedException {
        String fileName = "学生信息文件";
        Integer fileId = 0;
        Date time = new Date();

        ConcretePrototype concretePrototype = new ConcretePrototype(fileName, fileId, time);

        ConcretePrototype cloneA = (ConcretePrototype) concretePrototype.clone();
        ConcretePrototype cloneB = (ConcretePrototype) concretePrototype.clone();

        System.out.println(concretePrototype.hashCode());
        System.out.println(cloneA.hashCode());
        System.out.println(cloneB.hashCode());
        System.out.println("=========================");
        concretePrototype.show();
        cloneA.show();
        cloneB.show();

        System.out.println("==============================");

        time.setTime(999999999);
        concretePrototype.show();
        cloneA.show();
        cloneB.show();
    }
}

/*
执行构造方法
356573597
1735600054
21685669
=========================
文件名:学生信息文件
文件id:0
时间:Sat May 16 10:57:56 CST 2020
文件名:学生信息文件
文件id:0
时间:Sat May 16 10:57:56 CST 2020
文件名:学生信息文件
文件id:0
时间:Sat May 16 10:57:56 CST 2020
==============================
文件名:学生信息文件
文件id:0
时间:Mon Jan 12 21:46:39 CST 1970
文件名:学生信息文件
文件id:0
时间:Sat May 16 10:57:56 CST 2020
文件名:学生信息文件
文件id:0
时间:Sat May 16 10:57:56 CST 2020
*/

在这里插入图片描述

修改concretePrototype的属性time,cloneA和cloneB的属性没有被修改,还是一开始克隆出来的值

总结

  • 克隆的对象没有调用构造方法

    • 上面的例子已说明
  • clone方法源码

    •   protected native Object clone() throws CloneNotSupportedException;
      
    • 发现clone方法是一个本地方法,调用clone就去本地方法库调用其他语言(c++)

    • 创建实例化时,在内存中保存一份,克隆的时候直接去内存取

  • 当这个类很复杂时,克隆就可以避免消耗资源,时间

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值