谜一般的设计模式:原型模式

原型模式

  • 简单描述:创建对象的一种方式,相对于new方法创建对象,原型模式通过二进制流进行拷贝。说白了就是一个类实现Cloneable 接口。

  • 应用场景:

    1. 类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等,通过原型拷贝避免这些消耗
    2. 通过new一个对象需要非常繁琐的数据准备或访问权限,可以使用原型模式
    3. 一个对象有可能被其他对象访问,而且还有可能修改类里的属性状态等,若想保持原属性不变,需要使用原型模式。
  • 优点:

    创建对象快啊,直接通过二进制流拷贝,多香

  • 缺点:

    直接在内存中拷贝,构造函数是不会执行的

  • 代码

    浅复制

    @Data
    public class Car {
        private String color;
        private String plateNumber;
    }
    
    
    @Data
    public class Test implements Cloneable{
    	//引用类型
        private Car car;
    	//基本类型
        private int num;
    	//引用类型
        private String status;
    
        Test(){
            Car newCar = new Car();
            newCar.setColor("蓝宝石");
            newCar.setPlateNumber("辽A88888");
            this.car = newCar;
            System.out.println("我创建了一个car");
        }
        @Override
        public Object clone() throws CloneNotSupportedException{
            return super.clone();
        }
    
        public static void main(String[] args) throws CloneNotSupportedException {
            Test tt = new Test();
            tt.setNum(100);
            tt.setStatus("ff");
            Test tClone = (Test)tt.clone();
            tClone.getCar().setColor("红宝石");
            tClone.setNum(1);
            tClone.setStatus("s");
            System.out.println(JSON.toJSONString(tt));
            System.out.println(JSON.toJSONString(tClone));
    
        }
    }
    

    String 的特殊性

    这里说明一下,类分为基本类型和引用类型,当浅复制的时候基本类型可以自动实现克隆,属于值传递;而引用类型则是传递对象的引用,也就是复制出来的对象还是指向原来的地址,故此改变对象引用的值,肯定会影响原来的对象。那么String也是引用类型,为何它却可以实现深复制呢?究其根本String是一个final类,它是不可变的,当我们改变复制后的String的值,会产生一片新的内存空间,此时该对象的这个属性的引用将指向这片新的内存空间,此时两个对象的String类型的属性指向的就是不同的2片内存空间,改变一个不会影响到另一个,可以当做基本类型来使用。

    深复制

    ​ 深复制有两种方式,一种是复制的对象内部的引用类型也实现cloneable接口;另一种是实现Serializable接口,通过字节流序列化实现深拷贝。这里贴出第二种的代码(此代码摘自https://blog.csdn.net/zyxhangiian123456789/article/details/98630429)

    import java.io.ByteArrayInputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.io.Serializable;
     
    /**
     * 通过字节流序列化实现深拷贝,需要深拷贝的对象必须实现Serializable接口
     * 
     * @author Administrator
     */
    public class CloneUtils {
    	@SuppressWarnings("unchecked")
    	public static <T extends Serializable> T clone(T obj) {
    		T cloneObj = null;
    		try {
    			// 写入字节流
    			ByteArrayOutputStream out = new ByteArrayOutputStream();
    			ObjectOutputStream obs = new ObjectOutputStream(out);
    			obs.writeObject(obj);
    			obs.close();
     
    			// 分配内存,写入原始对象,生成新对象
    			ByteArrayInputStream ios = new ByteArrayInputStream(out.toByteArray());
    			ObjectInputStream ois = new ObjectInputStream(ios);
    			// 返回生成的新对象
    			cloneObj = (T) ois.readObject();
    			ois.close();
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    		return cloneObj;
    	}
    }
    

    综上,如果在深复制过程中有些类没有实现Serializable接口,或是不想让某些类进行复制,则可以在该对象的声明前加上transient关键字

    @Data
    public class Test implements Serializable{
    	//这样复制Test对象的时候这个Car就不会被复制,复制出来的对象中的car则是个null
        private transient Car car;
    
        private int num;
    
        private String status;
    }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值