java中的clone机制及序列化

    在实际编程过程中,我们常常要遇到这种情况:有一个对象A,在某一时刻A中已经包含了一些有效值,此时可能会需要一个和A完全相同新对象B,并且此后对B任何改动都不会影响到A中的值,也就是说,AB是两个独立的对象,但B的初始值是由A对象确定的。在这种情况下常常使用clone。当然你完全可以new一个新的,让后再进行赋值。但应用clone会有如下的好处:

     1、实现clone方法比较简单、方便。

     2、Object类的clone()一个native方法,native方法的效率一般来说都是远高于java中的非native方法,因此clone方法是高效的。

    注意;通过序列化的方式也可以实现clone。如果一个对象包含复杂类型的变量时,可用序列化或深度clone来实现对象的clone。

浅度复制和深度复制

  
    在java中,对于基本类型的数据可采用浅度复制的方式进行对象的复制,其中做法就是直接继承Cloneable接口,调用Object类的clone()方法就可以了。而对于非基本类型的数据,复制方法只能采用深度复制或序列化的方式进行复制。
    典型的实例:
/**
 * 
 * @功能   羊对象类  
 * @创建人   gao_jie
 * @创建日期 Jun 25, 2009
 * @版本     1.0
 * 
 */
public class Sheep implements Cloneable {
	
	private String name;//名字

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	
	/* (non-Javadoc)
	 * @see java.lang.Object#clone()
	 */
	public Object clone() throws CloneNotSupportedException {
		return super.clone();
	}
}

public class Sheepfold implements Cloneable {
	 public Sheep sheep;//羊对象
	 public String name;//羊圈名字
	 public int number;//数量

	 public Sheepfold() {
		 this.sheep = new Sheep();
	 }
	/* (non-Javadoc)
	 * @see java.lang.Object#clone()
	 */
	public Object clone() throws CloneNotSupportedException {
		return super.clone();
	}
}

public class Test {
	public static void main(String[] args) {
		// 声明一个小羊圈对象
		Sheepfold smallFold = new Sheepfold();
		smallFold.name = "小羊圈";
		smallFold.number = 10;
		smallFold.sheep.setName("小羊");
		// 复制羊圈
		Sheepfold bigFold = null;
		try {
			bigFold = (Sheepfold) smallFold.clone();
		} catch (CloneNotSupportedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		bigFold.name="大羊圈";
		bigFold.number=100;
		bigFold.sheep.setName("大羊");
		
		System.out.println("小羊圈输出信息如下:");
		System.out.println("smallFold.name="+smallFold.name);
		System.out.println("smallFold.number="+smallFold.number);
		System.out.println("smallFold.sheep="+smallFold.sheep.getName());
		System.out.println("大羊圈输出信息如下:");
		System.out.println("bigFold.name="+bigFold.name);
		System.out.println("bigFold.number="+bigFold.number);
		System.out.println("bigFold.sheep="+bigFold.sheep.getName());
	}
}
测试结果:
小羊圈输出信息如下:
smallFold.name=小羊圈
smallFold.number=10
smallFold.sheep=大羊
大羊圈输出信息如下:
bigFold.name=大羊圈
bigFold.number=100
bigFold.sheep=大羊
 
显然上面的这种复制是失败的,因为改动第二个对象中的名字后第一个对象的名字也发生了变化。要实现正确的复制,必须采用深度复制。其sheepfold类中clone方法的代码应改为如下:

把上面的例子改成深度clone很简单,只需将Sheepfold的clone()方法改为如下即可:
    public Object clone() throws CloneNotSupportedException {
        Sheepfold fold = (Sheepfold)super.clone();
        sheep = (Sheep)fold.sheep.clone();
        return fold;
    }
 另外,采用序列化也可以实现深度复制的效果。
代码如下:
/**
 * 
 * @功能   羊对象类  
 * @创建人   gao_jie
 * @创建日期 Jun 25, 2009
 * @版本     1.0
 * 
 */
public class Sheep implements Serializable{
	
	private String name;//名字

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
}

public class Sheepfold implements Cloneable, Serializable {
	public Sheep sheep;// 羊对象
	public String name;// 羊圈名字
	public int number;// 数量

	public Sheepfold() {
		this.sheep = new Sheep();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Object#clone()
	 */
	public Object clone() throws CloneNotSupportedException {
		try {
			ByteArrayOutputStream bos = new ByteArrayOutputStream();
			ObjectOutputStream oos = new ObjectOutputStream(bos);
			oos.writeObject(this);
			// 将流序列化
			ByteArrayInputStream bis = new ByteArrayInputStream(bos
					.toByteArray());
			ObjectInputStream ois = new ObjectInputStream(bis);
			return ois.readObject();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		return null;
	}
}
测试类
public class Test {
	public static void main(String[] args) {
		// 声明一个小羊圈对象
		Sheepfold smallFold = new Sheepfold();
		smallFold.name = "小羊圈";
		smallFold.number = 10;
		smallFold.sheep.setName("小羊");
		// 复制羊圈
		Sheepfold bigFold = null;
		try {
			bigFold = (Sheepfold) smallFold.clone();
		} catch (CloneNotSupportedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		bigFold.name="大羊圈";
		bigFold.number=100;
		bigFold.sheep.setName("大羊");
		
		System.out.println("小羊圈输出信息如下:");
		System.out.println("smallFold.name="+smallFold.name);
		System.out.println("smallFold.number="+smallFold.number);
		System.out.println("smallFold.sheep="+smallFold.sheep.getName());
		System.out.println("大羊圈输出信息如下:");
		System.out.println("bigFold.name="+bigFold.name);
		System.out.println("bigFold.number="+bigFold.number);
		System.out.println("bigFold.sheep="+bigFold.sheep.getName());
	}
}
测试结果:
小羊圈输出信息如下:
smallFold.name=小羊圈
smallFold.number=10
smallFold.sheep=小羊
大羊圈输出信息如下:
bigFold.name=大羊圈
bigFold.number=100
bigFold.sheep=大羊
 显然,序列化可以实现深度复制的效果,但每个非基本类型对象都必须是可序列化的。而设计模式中的原型啊模式也就是实现深度复制,因此,原型模式可以采用深度复制和序列化两种方式来实现。

       

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值