原型设计模式(浅克隆和深克隆)

原型模式用于创建重复对象并且保证性能,它属于是一种创建型的设计模式,提供了一种创建对象的最佳方式。


该设计模式用于实现一个原型接口,该接口用于创建当前对象的克隆对象。


应用实例场景:  可以想象成细胞分裂、克隆羊多利、孙悟空拔一根猴毛,吹出千万个。



首先我们有一个要被克隆的原始 羊 这个类如下:

public class Sheep implements Cloneable{

	private String name;
	
	private int age;
	//表示羊腿
	public Leg leg;
	
	public ArrayList<String>strs = new ArrayList<String>(); //set get 方法省略,这个时候这个Sheep类中的clone方法中没有进行任何特殊操作
}

羊腿类:

//羊腿类
public class Leg {
	
	private String leglong;
	private String legweight;
	public String getLeglong() {
		return leglong;
	}
	public void setLeglong(String leglong) {
		this.leglong = leglong;
	}
	public String getLegweight() {
		return legweight;
	}
	public void setLegweight(String legweight) {
		this.legweight = legweight;
	}
	
}


接下来写一个测试类进行克隆操作:

public class CloneCellTest {

	public static void main(String[] args) {

		Sheep cell1 = new Sheep();
		
		cell1.setName("普通绵羊");
		
		cell1.setAge(11);
		
		
		Leg l = new Leg();  l.setLeglong("120");  l.setLegweight("10");
		cell1.setLeg(l);
		
		ArrayList<String>list = new ArrayList();
		list.add("母羊");
		list.add("白色");
		list.add("40kg");
		
		
		cell1.setStrs(list);
		
		try {
			Sheep cell1clone = (Sheep) cell1.clone();
			
			
			System.out.println(cell1clone.getName());
			System.out.println(cell1clone.getAge());
			System.out.println(cell1clone.strs.size());
			
			System.out.println( cell1.strs == cell1clone.strs );
			System.out.println( cell1.leg == cell1clone.leg );
			
		} catch (CloneNotSupportedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	
}


执行  CloneCellTest的main方法,得到的结果如下:



注意到   这里    cell1.strs == cell1clone.strs    ,      cell1.leg == cell1clone.leg    

代表的是  被克隆的对象和克隆出来的对象  其 对象中的引用对象   Leg   和  List<String>strs  , 其指向的是同一地址,这样子的克隆被称之为 浅克隆,

浅克隆只克隆对象中的基本数据类型,包括    byte、short、int、long、float、double、boolean、char、String (八种基本数据类型和一个引用类型),

而对象中的其他非String引用对象类型则不会被克隆,如本例子中  Sheep  中的leg  和  List<String>strs


在实际开发中,更经常使用到的是深克隆,即对象中的对象也被克隆出来


接下来对程序进行一些改造:

Sheep  类中的clone方法重写成这样的

@Override
	protected Object clone() throws CloneNotSupportedException {
		// TODO Auto-generated method stub
		
		Sheep sheepClone = null;
		if(sheepClone==null){
			
			sheepClone = (Sheep) super.clone();
			sheepClone.strs =  (ArrayList<String>)(this.strs.clone());
			
		}
		return sheepClone;
		//return super.clone();
		
	}


然后再次调用  CloneCellTest的main方法,得到结果如下:




注意到 Sheep类的clone方法中调用了 ArrayList 的 clone 方法,所以说,当 Sheep 对象进行克隆后的产生的克隆对象 和 原始sheep中的 strs 不再指向同一个地址,自此,完成了部分深克隆。

但是有的时候我们的对象中的对象 如果不是那么方便的访问其属性,不能够对其clone方法进行改写的时候,这个时候应该使用字节流加上序列化的方法完成对对象的深克隆。


这个时候  Sheep 和 Leg 两个类都要实现  Serilizable  接口,以便序列化,代码如下:

Sheep类:

public class Sheep implements Cloneable,Serializable{

	private String name;
	
	private int age;
	//表示羊腿
	public Leg leg;
	
	public ArrayList<String>strs = new ArrayList<String>();    //set  和 get 方法省略
       ........................................
@Override
	protected Object clone() throws CloneNotSupportedException {
		// TODO Auto-generated method stub
		
		ByteArrayOutputStream bos = null ;
		ObjectOutputStream oos = null ;
		ByteArrayInputStream bis = null ;
		ObjectInputStream ois  = null ;
		try {
			//直接super.clone() 这个是浅克隆,只克隆八大基本数据类型   return super.clone();
			//序列化
			 bos = new ByteArrayOutputStream();
			 oos = new ObjectOutputStream(bos);
			oos.writeObject(this);
			
			
			//反序列化
			 bis = new ByteArrayInputStream( bos.toByteArray() );
			 ois = new ObjectInputStream( bis );
			Sheep copy = (Sheep) ois.readObject();
			
			
			return copy;
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return null;
		}finally{
			try {
				bos.close();
				oos.close();
				bis.close();
				ois.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
	}

}
	



Leg类:

//羊腿类
public class Leg implements Serializable{
	
	private String leglong;
	private String legweight;
	public String getLeglong() {
		return leglong;
	}
	public void setLeglong(String leglong) {
		this.leglong = leglong;
	}
	public String getLegweight() {
		return legweight;
	}
	public void setLegweight(String legweight) {
		this.legweight = legweight;
	}
	
}


测试类:

public class CloneCellTest {

	public static void main(String[] args) {

		Sheep cell1 = new Sheep();
		
		cell1.setName("普通绵羊");
		
		cell1.setAge(11);
		
		
		Leg l = new Leg();  l.setLeglong("120");  l.setLegweight("10");
		cell1.setLeg(l);
		
		ArrayList<String>list = new ArrayList();
		list.add("母羊");
		list.add("白色");
		list.add("40kg");
		
		
		cell1.setStrs(list);
		
		try {
			Sheep cell1clone = (Sheep) cell1.clone();
			
			
			System.out.println(cell1clone.getName());
			System.out.println(cell1clone.getAge());
			System.out.println(cell1clone.strs.size());
			
			System.out.println( cell1.strs == cell1clone.strs );
			System.out.println( cell1.leg == cell1clone.leg );
			
		} catch (CloneNotSupportedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	
}

输出结果如下:


看到 输出的  克隆和 被克隆对象里面的引用 两个地址是不同的,至此完成 深度克隆。







  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值