A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

【java_设计模式】原型模式、浅拷贝和深拷贝
  • 应用场景
    需要同一个类的多个不同对象完成业务操作,群发email,需要多个Mail类的对象
    好处:提高性能
[Java] 纯文本查看 复制代码
 public static void main(String[] args) throws CloneNotSupportedException {
        Mail mail = new Mail();
        mail.setContent("初始化模板");
        for(int i=0; i<10; i++) {
             //创建10个Mail的对象进行发邮件的操作,使用原型模式加快性能
            Mail mailTemp = (Mail) mail.clone();
            mailTemp.setName("第" + i + "个克隆出来的对象");
            // 使用克隆采用的是二进制的拷贝,效率比直接new高很多
        }
        // 不改变原来的Mail
        MailUtil.saveOriginMailRecord(mail);
    }



  • 实现
[Java] 纯文本查看 复制代码
// 省略get set方法
public class Mail implements Cloneable{
    private String name;
    private String address;
    private String content;
    public Mail() {
        System.out.println("Mail Class Constructor");
    }

    /**
     * 记得重写方法
     * @return
     * @throws CloneNotSupportedException
     */
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    @Override
    public String toString() {
        return "Mail{" +
                "name='" + name + '\'' +
                ", address='" + address + '\'' +
                ", content='" + content + '\'' +
                '}';
    }
}



[Java] 纯文本查看 复制代码
public class MailUtil {
    public static void sendMail(Mail mail) {
        String outputContent = "向{0}同学,邮件地址{1},邮件内容:{2},发送成功";
        System.out.println(MessageFormat.format(outputContent, mail.getName(),mail.getAddress(),mail.getContent()));
    }

    public static void saveOriginMailRecord(Mail mail) {
      System.out.println("存储originMail记录,originMail:" + mail.getContent());
    }
}


  • 原理

原型模式的本质是类继承Clonable接口,重写clone方法。clone的底层是使用二进制拷贝,需要多个对象的时候可以用该方法取代多次new,提高性能。




修改原对象的成员变量,可能会同时修改克隆出来的对象。避免这种坑即使用深拷贝。
不重写clone方法,默认使用浅拷贝

[Java] 纯文本查看 复制代码
public class Pig implements Cloneable{
    private String name;
    // 引用对象
    private Date birthday;
    
    // 默认的clone方法,不会修改引用对象的指向,即拷贝出来的对象中birthday引用指向的是同一块内存区域
    @Override
    protected Object clone() throws CloneNotSupportedException {
        Pig pig = (Pig)super.clone();

        // 深拷贝,有引用对象的时候需要重写clone()方法
        pig.birthday = (Date)pig.birthday.clone();
        return pig;
    }
}



  • 拓展
    原型模式和单例模式结合的时候,注意修改clone方法

1.极端场景

[Java] 纯文本查看 复制代码
// step 2克隆破坏单例
        HungrySingleton hungrySingleton = HungrySingleton.getInstance();
        Method method = hungrySingleton.getClass().getDeclaredMethod("clone");
        method.setAccessible(true);
        HungrySingleton cloneHungrySingleton = (HungrySingleton) method.invoke(hungrySingleton);
        System.out.println(hungrySingleton);
        System.out.println(cloneHungrySingleton);

2.关键代码

[Java] 纯文本查看 复制代码
 /**
     * 单例模式下使用的clone方法, 防止克隆破坏就要修改方法实现
     * @return
     * @throws CloneNotSupportedException
     */
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return getInstance();
    }


---------------------
作者:Ch.yang
来源:CSDN
原文:https://blog.csdn.net/chenghan_yang/article/details/90548613
版权声明:本文为博主原创文章,转载请附上博文链接!


0 个回复

您需要登录后才可以回帖 登录 | 加入黑马