创建型设计模式(2)-- 原型模式

一、名称:

      原型模式

 

二、概念:

      针对一个原型实例,通过对其的拷贝而创建出与其类似的新实例。

     通过这个概念,我们将这个概念拆分成三个方面:

(1) 一个现成的实例对象(这个也就是模式名字中所说的原型),一个支持拷贝方法的对象

(2)拷贝方法,在java中,指得就是object中的clone()方法

(3)生成的新对象

    原型模式,简单粗暴点来说,就可以总结为,通过clone方法创建新对象的一种对象创建模式。

三、适用场景

   (1) 需要重复创建的对象比较大或者数量比较多,改用原型模式创建,效率会比new的方式要高,尤其是对象越大越复杂或者需要创建的对象越多,差距越明显(这是因为Object的clone()方法是一个本地方法,直接操作内存中的二进制流,简化了对象的创建流程);

  (2) 想绕过访问权限创建对象,原型模式创建对象,不需要调用对象的构造方法,因此不受访问权限的控制(比如所述的单例模式,构造方法私有化,就不能通过new来创建)。

 (3)新创建的对象每次初始化的属性值基本一致时,可以通过原始模式创建,不需要每次都重复执行赋值。

 (4) 给定一个对象,无法确认其具体类型时,可以使用克隆方式来创建。

四、具体实现

      原型模式可以分为两类,深克隆和浅克隆,但不管是深克隆还是浅克隆,如果需要使用原型模式创建对象,都需要实现Cloneable接口,只有实现了Cloneable接口的对象才可以使用clone() 方法,否则会抛出CloneNotSupportedException异常。

具体见下面Object中的clone()源码:

     /*The method {@code clone} for class {@code Object} performs a
     * specific cloning operation. First, if the class of this object does
     * not implement the interface {@code Cloneable}, then a
     * {@code CloneNotSupportedException} is thrown. Note that all arrays
     * are considered to implement the interface {@code Cloneable} and that
     * the return type of the {@code clone} method of an array type {@code T[]}
     * is {@code T[]} where T is any reference or primitive type.
     * Otherwise, this method creates a new instance of the class of this
     * object and initializes all its fields with exactly the contents of
     * the corresponding fields of this object, as if by assignment; the
     * contents of the fields are not themselves cloned. Thus, this method
     * performs a "shallow copy" of this object, not a "deep copy" operation.
     * <p>
     * The class {@code Object} does not itself implement the interface
     * {@code Cloneable}, so calling the {@code clone} method on an object
     * whose class is {@code Object} will result in throwing an
     * exception at run time.
     *
     * @return     a clone of this instance.
     * @throws  CloneNotSupportedException  if the object's class does not
     *               support the {@code Cloneable} interface. Subclasses
     *               that override the {@code clone} method can also
     *               throw this exception to indicate that an instance cannot
     *               be cloned.
     * @see java.lang.Cloneable
     */
    protected native Object clone() throws CloneNotSupportedException;

       Cloneable接口本身其实是一个空接口,里面没有任何属性和方法,其只是一种标识,实现了Cloneable就标识,该类是支持clone()方法的,这样的接口在java中有不少,还比如序列号接口Serializable也是这样的一种作用。

/**
 * A class implements the <code>Cloneable</code> interface to
 * indicate to the {@link java.lang.Object#clone()} method that it
 * is legal for that method to make a
 * field-for-field copy of instances of that class.
 * <p>
 * Invoking Object's clone method on an instance that does not implement the
 * <code>Cloneable</code> interface results in the exception
 * <code>CloneNotSupportedException</code> being thrown.
 * <p>
 * By convention, classes that implement this interface should override
 * <tt>Object.clone</tt> (which is protected) with a public method.
 * See {@link java.lang.Object#clone()} for details on overriding this
 * method.
 * <p>
 * Note that this interface does <i>not</i> contain the <tt>clone</tt> method.
 * Therefore, it is not possible to clone an object merely by virtue of the
 * fact that it implements this interface.  Even if the clone method is invoked
 * reflectively, there is no guarantee that it will succeed.
 *
 * @author  unascribed
 * @see     java.lang.CloneNotSupportedException
 * @see     java.lang.Object#clone()
 * @since   JDK1.0
 */
public interface Cloneable {
}

     说完了原型模式的前提条件,再来看看深克隆和浅克隆,二者的区别主要是体现在对引用对象的拷贝上面,浅克隆仅支持对基本类型(和他们对应的包装类)和String类型数据的拷贝,对于引用类型,仅拷贝句柄(这会导致原型对象和拷贝对象的某一属性句柄是指向的是同一个对象),而不拷贝后面具体对象的内容。而深克隆则可以自行实现对引用对象拷贝的逻辑,实现对引用对象属性的拷贝。

   (1)浅克隆

     Object对象clone() 方法就是浅克隆。

     浅克隆比较简单,我们直接看一下浅克隆对于它们擅长的基本类型和String类型数据的拷贝。

       首先创建一个类ShallowPrototype,该类实现了Cloneable接口,重写了clone()方法,调用object的clone()方法返回即可(这里必须这样重写实现一下,主要Object中clone()方法由于可见性原因无法直接调用),为了验证浅克隆对于基本类型(这里用的是包装类,基本类型是值拷贝,肯定是没有问题的)和String类型的拷贝,每种类型举了一个例子。

public class ShallowPrototype implements Cloneable{
	
	
	private String StrCopy ;
	
	private Integer IntCopy;
	
	private Boolean BooCopy;
	
	private Character CharCopy;
	
	private Byte byteCopy;
	
	private Short ShorCopy;
	
	private Long longCopy;
	
	private Float floCopy;
	
	private Double douCopy;
	

    
	
	public String getStrCopy() {
		return StrCopy;
	}

	public void setStrCopy(String strCopy) {
		StrCopy = strCopy;
	}

	public Integer getIntCopy() {
		return IntCopy;
	}

	public void setIntCopy(Integer intCopy) {
		IntCopy = intCopy;
	}

	public Boolean getBooCopy() {
		return BooCopy;
	}

	public void setBooCopy(Boolean booCopy) {
		BooCopy = booCopy;
	}

	public Character getCharCopy() {
		return CharCopy;
	}

	public void setCharCopy(Character charCopy) {
		CharCopy = charCopy;
	}

	public Byte getByteCopy() {
		return byteCopy;
	}

	public void setByteCopy(Byte byteCopy) {
		this.byteCopy = byteCopy;
	}

	public Short getShorCopy() {
		return ShorCopy;
	}

	public void setShorCopy(Short shorCopy) {
		ShorCopy = shorCopy;
	}

	public Long getLongCopy() {
		return longCopy;
	}

	public void setLongCopy(Long longCopy) {
		this.longCopy = longCopy;
	}

	public Float getFloCopy() {
		return floCopy;
	}

	public void setFloCopy(Float floCopy) {
		this.floCopy = floCopy;
	}

	public Double getDouCopy() {
		return douCopy;
	}

	public void setDouCopy(Double douCopy) {
		this.douCopy = douCopy;
	}

	@Override
	public String toString() {
		return "ShallowPrototype [StrCopy=" + StrCopy + ", IntCopy=" + IntCopy + ", BooCopy=" + BooCopy + ", CharCopy="
				+ CharCopy + ", byteCopy=" + byteCopy + ", ShorCopy=" + ShorCopy + ", longCopy=" + longCopy
				+ ", floCopy=" + floCopy + ", douCopy=" + douCopy + "]";
	}

	@Override
	public Object clone() throws CloneNotSupportedException {
		return super.clone();
	}
	
}

    下面是测试代码,首先初始化了一个shallow 对象,给每个属性都设置了值,然后生成一个克隆对象shallow1,这时候,将

shallow 对象和shallow1分别打印一下,然后将shallow1中所有对象中的值都进行了变更,然后再次打印shallow 和shallow1

	@Test
	void TestShallowPrototype() {
		ShallowPrototype shallow = new ShallowPrototype();
		shallow.setBooCopy(true);
		shallow.setByteCopy("2".getBytes()[0]);
		shallow.setCharCopy('2');
		shallow.setDouCopy(2.00);
		shallow.setFloCopy(2.0f);
		shallow.setIntCopy(2);
		shallow.setLongCopy(2l);
		shallow.setShorCopy(Short.parseShort("2"));
		shallow.setStrCopy("2");
		try {
			ShallowPrototype shallow1=(ShallowPrototype) shallow.clone();
			System.out.println("shallow===before===>>"+shallow.toString());
		    System.out.println("shallow1===before===>>"+shallow1.toString());
			shallow1.setBooCopy(false);
			shallow1.setByteCopy("3".getBytes()[0]);
			shallow1.setCharCopy('3');
			shallow1.setDouCopy(3.00);
			shallow1.setFloCopy(3.0f);
			shallow1.setIntCopy(3);
			shallow1.setLongCopy(3l);
			shallow1.setShorCopy(Short.parseShort("3"));
			shallow1.setStrCopy("3");
			System.out.println("shallow===after===>>"+shallow.toString());
		    System.out.println("shallow1===after===>>"+shallow1.toString());
		     
		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}

     拷贝效果如下:

shallow===before===>>ShallowPrototype [StrCopy=2, IntCopy=2, BooCopy=true, CharCopy=2, byteCopy=50, ShorCopy=2, longCopy=2, floCopy=2.0, douCopy=2.0]
shallow1===before===>>ShallowPrototype [StrCopy=2, IntCopy=2, BooCopy=true, CharCopy=2, byteCopy=50, ShorCopy=2, longCopy=2, floCopy=2.0, douCopy=2.0]
shallow===after===>>ShallowPrototype [StrCopy=2, IntCopy=2, BooCopy=true, CharCopy=2, byteCopy=50, ShorCopy=2, longCopy=2, floCopy=2.0, douCopy=2.0]
shallow1===after===>>ShallowPrototype [StrCopy=3, IntCopy=3, BooCopy=false, CharCopy=3, byteCopy=51, ShorCopy=3, longCopy=3, floCopy=3.0, douCopy=3.0]

    经由测试,我可以发现,经过拷贝shallow1完整的获取到了shallow所有的基本类型(包装类)和String类型的值。将shallow1的值进行修改后,shallow完全不受影响,还保持着之前的初始值。

 

 下面,我们再测试下浅克隆下,对于其他类型,比如自定义对象,数组,集合等对象的克隆支持,代码同上面的ShallowPrototype基本差不多,只是里面的具体属性换成了对象,数据,集合,具体代码如下:

public class ShallowPrototypeFailure implements Cloneable{
    
	
	   private ShallowPrototype prototype;
	   
	   private String[] strArr;
	   
	   private List<String> strList;
	   
	   private Set<String> strSet;
	   
	   private Map<String,Object> strMap;
	   

	public ShallowPrototype getPrototype() {
		return prototype;
	}

	public void setPrototype(ShallowPrototype prototype) {
		this.prototype = prototype;
	}

	public String[] getStrArr() {
		return strArr;
	}

	public void setStrArr(String[] strArr) {
		this.strArr = strArr;
	}

	public List<String> getStrList() {
		return strList;
	}

	public void setStrList(List<String> strList) {
		this.strList = strList;
	}

	public Set<String> getStrSet() {
		return strSet;
	}

	public void setStrSet(Set<String> strSet) {
		this.strSet = strSet;
	}

	public Map<String, Object> getStrMap() {
		return strMap;
	}

	public void setStrMap(Map<String, Object> strMap) {
		this.strMap = strMap;
	}
	
	

	@Override
	public String toString() {
		return "ShallowPrototypeFailure [prototype=" + prototype + ", strArr=" + Arrays.toString(strArr) + ", strList="
				+ strList + ", strSet=" + strSet + ", strMap=" + strMap + "]";
	}

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

  下面也同样来进行一下测试,策略同上,我新建了一个对象failure,分别给里面的属性设置初始值,然后执行克隆操作得到一个新的对象failure1,分别打印failure和failure1来对比两个对象的属性值, 然后再对failure1里面的属性值增加了新值,再次分别打印failure和failure1,具体的代码见下:

@Test
	public void testShallowPrototypeFailure() {
		ShallowPrototypeFailure failure = new ShallowPrototypeFailure();
		
		ShallowPrototype prototype = new ShallowPrototype();
		prototype.setBooCopy(true);
		prototype.setCharCopy('2');
		failure.setPrototype(prototype);
		
		String[] strArr = new String[4];
		strArr[0]="0";
		strArr[1]="1";
		strArr[2]="2";
		failure.setStrArr(strArr);
		
		List<String> strList = Lists.newArrayList("0","1","2");
		failure.setStrList(strList);
		
		Set<String> strSet = Sets.newHashSet("0","1","2");
		failure.setStrSet(strSet);
		
		Map<String,Object> strMap= Maps.newHashMap();
		strMap.put("0",0);
		strMap.put("1",1);
		strMap.put("2",2);
		failure.setStrMap(strMap);
		
		try {
			ShallowPrototypeFailure failure1 = (ShallowPrototypeFailure) failure.clone();
			
			System.out.println("failure===before===>>"+failure.toString());
		    System.out.println("failure1===before===>>"+failure1.toString());
		    
		     ShallowPrototype prototype1 = failure1.getPrototype();
		     prototype1.setBooCopy(false);
		     prototype1.setCharCopy('3');
		     
		     List<String> strList1 = failure1.getStrList();
		     strList1.add("4");
		     
		     
		     String[] strArr1 = failure1.getStrArr();
		     strArr1[3] = "3";
		     
		     Set<String> strSet1 = failure1.getStrSet();
		     strSet1.add("3");
		     
		     Map<String, Object> strMap1 = failure1.getStrMap();
		     strMap1.put("3", 3);
		     
		     System.out.println("failure===after===>>"+failure.toString());
			 System.out.println("failure1===after===>>"+failure1.toString());
		    
		} catch (Exception e) {
			e.printStackTrace();
		}
		
	
	}

  测试结果如下:

failure===before===>>ShallowPrototypeFailure [prototype=ShallowPrototype [StrCopy=null, IntCopy=null, BooCopy=true, CharCopy=2, byteCopy=null, ShorCopy=null, longCopy=null, floCopy=null, douCopy=null], strArr=[0, 1, 2, null], strList=[0, 1, 2], strSet=[0, 1, 2], strMap={0=0, 1=1, 2=2}]
failure1===before===>>ShallowPrototypeFailure [prototype=ShallowPrototype [StrCopy=null, IntCopy=null, BooCopy=true, CharCopy=2, byteCopy=null, ShorCopy=null, longCopy=null, floCopy=null, douCopy=null], strArr=[0, 1, 2, null], strList=[0, 1, 2], strSet=[0, 1, 2], strMap={0=0, 1=1, 2=2}]
failure===after===>>ShallowPrototypeFailure [prototype=ShallowPrototype [StrCopy=null, IntCopy=null, BooCopy=false, CharCopy=3, byteCopy=null, ShorCopy=null, longCopy=null, floCopy=null, douCopy=null], strArr=[0, 1, 2, 3], strList=[0, 1, 2, 4], strSet=[0, 1, 2, 3], strMap={0=0, 1=1, 2=2, 3=3}]
failure1===after===>>ShallowPrototypeFailure [prototype=ShallowPrototype [StrCopy=null, IntCopy=null, BooCopy=false, CharCopy=3, byteCopy=null, ShorCopy=null, longCopy=null, floCopy=null, douCopy=null], strArr=[0, 1, 2, 3], strList=[0, 1, 2, 4], strSet=[0, 1, 2, 3], strMap={0=0, 1=1, 2=2, 3=3}]

  根据测试结果打印的内容,我们可以发现浅克隆,克隆的是对象的引用,当我们改变克隆对象的属性时,同时也会引起原型对象属性的变动。

 这个结果是我们想看到的吗?显然不是,我们通过克隆需要得到的是一个全新的的对象,我可以任意更改原型对象和克隆对象的属性值,而不应该担心之间的彼此牵连,而投鼠忌器。如何实现我们想要的效果呢?深克隆是对这个问题解决的答案。

  (2)深克隆

    深克隆就要求,类中的每个引用类型都实现了Clonable接口,并实现了自己的深克隆方法。在拷贝的过程中,需要将所有引用类型的属性全部深克隆一遍,以彻底解除原型对象对克隆对象的影响。

    下面举个例子来进行具体的说明,我创建了个DeapPrototype类,里面的属性和上面的ShallowPrototypeFailure是一模一样的(为了方便重写克隆方法,这里将List,Set,Map替换成了具体的类型),区别是重写的clone方法,在clone方法里面为每个对象属性都分别实现了深克隆的逻辑:

   对于shallowPrototype对象,直接调用了ShallowPrototype类重写的clone方法;

   String[],ArrayList,HashSet,HashMap分别调用自己的clone方法,此处一个数组和三个集合都存放的是String,如果里面存放的是其他自定义对象,该对象需要重写自己的克隆方法。

   这里举的例子比较简单,基本只有一级引用对象,如果引用对象的属性里面又包含引用对象,那么次级或者再深入的层层等级的引用对象必须实现cloneable接口,并且重写符合自己情况的深克隆方法。对于没有实现cloneable接口的对象,只能通过其他的方式创建,然后再拷贝里面的值。

  具体代码见下:

public class DeapPrototype implements Cloneable{
     
	
	  private ShallowPrototype prototype;
	   
	   private String[] strArr;
	   
	   private ArrayList<String> strList;
	   
	   private HashSet<String> strSet;
	   
	   private HashMap<String,Object> strMap;
	   

	public ShallowPrototype getPrototype() {
		return prototype;
	}

	public void setPrototype(ShallowPrototype prototype) {
		this.prototype = prototype;
	}

	public String[] getStrArr() {
		return strArr;
	}

	public void setStrArr(String[] strArr) {
		this.strArr = strArr;
	}

	public ArrayList<String> getStrList() {
		return strList;
	}

	public void setStrList(ArrayList<String> strList) {
		this.strList = strList;
	}

	public HashSet<String> getStrSet() {
		return strSet;
	}

	public void setStrSet(HashSet<String> strSet) {
		this.strSet = strSet;
	}

	public HashMap<String, Object> getStrMap() {
		return strMap;
	}

	public void setStrMap(HashMap<String, Object> strMap) {
		this.strMap = strMap;
	}

	@Override
	public String toString() {
		return "DeapPrototype [prototype=" + prototype + ", strArr=" + Arrays.toString(strArr) + ", strList=" + strList
				+ ", strSet=" + strSet + ", strMap=" + strMap + "]";
	}

	@Override
	public Object clone() throws CloneNotSupportedException {
		DeapPrototype deapPrototype = null;
		try {
			deapPrototype = (DeapPrototype) super.clone();
			deapPrototype.prototype = (ShallowPrototype) this.getPrototype().clone();
			deapPrototype.strArr = this.getStrArr().clone();
			deapPrototype.strList = (ArrayList<String>) this.getStrList().clone();
			deapPrototype.strSet = (HashSet<String>) this.getStrSet().clone();	
			deapPrototype.strMap = (HashMap<String, Object>) this.getStrMap().clone();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return deapPrototype;
	}   
}

  测试代码:

  

@Test
	public void testDeapPrototype() {
		DeapPrototype deep = new DeapPrototype();
		//初始化浅克隆对象
		ShallowPrototype shallow = new ShallowPrototype();
		shallow.setBooCopy(true);
		shallow.setByteCopy("2".getBytes()[0]);
		shallow.setCharCopy('2');
		shallow.setDouCopy(2.00);
		shallow.setFloCopy(2.0f);
		shallow.setIntCopy(2);
		shallow.setLongCopy(2l);
		shallow.setShorCopy(Short.parseShort("2"));
		shallow.setStrCopy("2");
		deep.setPrototype(shallow);
		//初始化数组
		String[] strArr = new String[4];
		strArr[0]="0";
		strArr[1]="1";
		strArr[2]="2";
		deep.setStrArr(strArr);
		//初始化列表
		ArrayList<String> strList = Lists.newArrayList("0","1","2");
		deep.setStrList(strList);
		//初始化Set集合
		HashSet<String> strSet = Sets.newHashSet("0","1","2");
		deep.setStrSet(strSet);
		//初始化map
		HashMap<String,Object> strMap= Maps.newHashMap();
		strMap.put("0",0);
		strMap.put("1",1);
		strMap.put("2",2);
		deep.setStrMap(strMap);
		
		try {
			DeapPrototype deep2 = (DeapPrototype) deep.clone();
			System.out.println("deep===before===>>"+deep.toString());
		    System.out.println("deep2===before===>>"+deep2.toString());
		    
		    ShallowPrototype prototype1 = deep2.getPrototype();
		     prototype1.setBooCopy(false);
		     prototype1.setCharCopy('3');
		     
		     List<String> strList1 = deep2.getStrList();
		     strList1.add("4");
		     
		     
		     String[] strArr1 = deep2.getStrArr();
		     strArr1[3] = "3";
		     
		     Set<String> strSet1 = deep2.getStrSet();
		     strSet1.add("3");
		     
		     Map<String, Object> strMap1 = deep2.getStrMap();
		     strMap1.put("3", 3);
		     
		     System.out.println("deep===after===>>"+deep.toString());
			 System.out.println("deep2===after===>>"+deep2.toString());
		    
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

  测试结果:

deep===before===>>DeapPrototype [prototype=ShallowPrototype [StrCopy=2, IntCopy=2, BooCopy=true, CharCopy=2, byteCopy=50, ShorCopy=2, longCopy=2, floCopy=2.0, douCopy=2.0], strArr=[0, 1, 2, null], strList=[0, 1, 2], strSet=[0, 1, 2], strMap={0=0, 1=1, 2=2}]
deep2===before===>>DeapPrototype [prototype=ShallowPrototype [StrCopy=2, IntCopy=2, BooCopy=true, CharCopy=2, byteCopy=50, ShorCopy=2, longCopy=2, floCopy=2.0, douCopy=2.0], strArr=[0, 1, 2, null], strList=[0, 1, 2], strSet=[0, 1, 2], strMap={0=0, 1=1, 2=2}]
deep===after===>>DeapPrototype [prototype=ShallowPrototype [StrCopy=2, IntCopy=2, BooCopy=true, CharCopy=2, byteCopy=50, ShorCopy=2, longCopy=2, floCopy=2.0, douCopy=2.0], strArr=[0, 1, 2, null], strList=[0, 1, 2], strSet=[0, 1, 2], strMap={0=0, 1=1, 2=2}]
deep2===after===>>DeapPrototype [prototype=ShallowPrototype [StrCopy=2, IntCopy=2, BooCopy=false, CharCopy=3, byteCopy=50, ShorCopy=2, longCopy=2, floCopy=2.0, douCopy=2.0], strArr=[0, 1, 2, 3], strList=[0, 1, 2, 4], strSet=[0, 1, 2, 3], strMap={0=0, 1=1, 2=2, 3=3}]

 通过结果,我们可以看出,经过克隆方法的重写,原型对象和克隆对象已经完全独立。

 以上是主流的深克隆方法,除此之外,还可以利用序列化和反序列化的特性来完成深克隆。想要利用序列化和反序列化来实现深克隆,原型对象必须实现了Serializable接口(这个接口和Cloneable一样,也是个空接口,实现了该接口,即表示该类可以被序列化),原型对象内部的所有引用对象的属性必须也实现了Serializable接口,否则会报错(如果该属性不需要被克隆,可以加上Transient)。

 同样,举个例子,代码如下,ShallowPrototype类的代码再次就不再展示,和之前基本一样,只是多现实了一个Serializable接口,这里需要特别说明的是为了防止对象被修改后反序列化报错,类里面要加上serialVersionUID。

 原型类

public class DeapBySerialize implements Serializable{
     
	
	  /**
	 * 
	 */
	private static final long serialVersionUID = -4436703333583692329L;
	

	private ShallowPrototype prototype;
	   
	   private String[] strArr;
	   
	   private List<String> strList;
	   
	   private Set<String> strSet;
	   
	   private Map<String,Object> strMap;
	   

	public ShallowPrototype getPrototype() {
		return prototype;
	}

	public void setPrototype(ShallowPrototype prototype) {
		this.prototype = prototype;
	}

	public String[] getStrArr() {
		return strArr;
	}

	public void setStrArr(String[] strArr) {
		this.strArr = strArr;
	}

	public List<String> getStrList() {
		return strList;
	}

	public void setStrList(List<String> strList) {
		this.strList = strList;
	}

	public Set<String> getStrSet() {
		return strSet;
	}

	public void setStrSet(Set<String> strSet) {
		this.strSet = strSet;
	}

	public Map<String, Object> getStrMap() {
		return strMap;
	}

	public void setStrMap(Map<String, Object> strMap) {
		this.strMap = strMap;
	}

   克隆工具类

public class SerializableCopy {
	
	
	
	public static Object deepClone(Object object) {
		ByteArrayOutputStream byteOutput  = null;
		ObjectOutputStream objOutPut = null;
		ByteArrayInputStream byteInPut = null;
		ObjectInputStream objInPut = null;
		try {
			byteOutput = new ByteArrayOutputStream();
			objOutPut = new ObjectOutputStream(byteOutput);
			objOutPut.writeObject(object);
			byte[] byteArray = byteOutput.toByteArray();
			byteInPut = new ByteArrayInputStream(byteArray);
			objInPut = new ObjectInputStream(byteInPut);
			return objInPut.readObject();
		} catch(Exception e) {
			e.printStackTrace();
		}finally {
			try {
				objOutPut.close();
				byteOutput.close();
				byteInPut.close();
				objInPut.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return null;
	}

测试代码

@Test
	public void testDeapBySerialize() {
		DeapBySerialize serialize = new DeapBySerialize();
		//初始化浅克隆对象
		ShallowPrototype shallow = new ShallowPrototype();
		shallow.setBooCopy(true);
		shallow.setByteCopy("2".getBytes()[0]);
		shallow.setCharCopy('2');
		shallow.setDouCopy(2.00);
		shallow.setFloCopy(2.0f);
		shallow.setIntCopy(2);
		shallow.setLongCopy(2l);
		shallow.setShorCopy(Short.parseShort("2"));
		shallow.setStrCopy("2");
		serialize.setPrototype(shallow);
		//初始化数组
		String[] strArr = new String[4];
		strArr[0]="0";
		strArr[1]="1";
		strArr[2]="2";
		serialize.setStrArr(strArr);
		//初始化列表
		List<String> strList = Lists.newArrayList("0","1","2");
		serialize.setStrList(strList);
		//初始化Set集合
		Set<String> strSet = Sets.newHashSet("0","1","2");
		serialize.setStrSet(strSet);
		//初始化map
		Map<String,Object> strMap= Maps.newHashMap();
		strMap.put("0",0);
		strMap.put("1",1);
		strMap.put("2",2);
		serialize.setStrMap(strMap);
		
		DeapBySerialize serialize2 = (DeapBySerialize) SerializableCopy.deepClone(serialize);
		 System.out.println("serialize======>>"+serialize);
		 System.out.println("serialize2======>>"+serialize2);
	}

 测试结果 

serialize======>>com.example.demo.prototype.DeapBySerialize@4eed2acf
serialize2======>>com.example.demo.prototype.DeapBySerialize@6c518474

 通过测试结果可以看出,反序列化后的对象地址已不同,说明已经是不同的对象(之前被序列化变成二进制流的对象是原型对象的一个拷贝,原型对象仍存在在内存中),通过反序列化也可以实现深克隆的功能(这也是破坏单例的方式之一,但是这个问题很好解决,不实现Serializable接口,就无法被破坏)。

通过序列化和反序列化来克隆对象,比较方便,不需要给所有的引用对象都实现克隆方法,尤其是对于那种引用对象层级很深的对象的克隆较为方便,较少的代码量就可以实现功能。但是它也是有缺点的,对象和流转化来转化去,速度相对于重写克隆的方法来说,会比较慢。到底使用什么方式,需要具体情况具体分析,综合选择最为优势的实现方式。

五、优点

     (1) 简化类的创建,对于属性值重复度比较高的复杂对象的大量创建尤其适合。

   (2)可以不使用构造器创建对象,对于那些构造器私有化的类创建对象比较有意义。

六、缺点

  (1)增加了代码的复杂性,需要增添克隆逻辑,尤其是对于属性对象层级比较多的深克隆,实现起来比较麻烦。

  (2)需要实现额外的接口,对于没有实现该接口的属性,还需要额外想办法处理。

 

七、注意点

       当类中有属性是引用对象时,需要确保实现的是深克隆;

      如果决定使用序列化反序列化方式实现深克隆,注意性能;

八、使用概率

      不高

       

    

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值