java中的clone技术

 编程过程中常常遇到如下情况: 假设有一个对象obj1,在某处需要和obj1一样的实例obj2,强调obj1和obj2是两个独立的实例,只是在开始的时候,它们具有一样的属性。这种情况下,一般的一种解决方法是:重新new一个对象obj2,然后将obj1的属性字段值依次赋予obj2。该种方法可行,但是也比较土。java提供了clone方法,使用clone方法,我们可以高效地解决上述的问题。

       在理解clone方法前,有必要先了解下浅拷贝(shallow copy)和深拷贝(deep copy)。先看一个与浅拷贝相关的代码段:

public class FamilyInfo {
	public String address;
	public int memberNum;
	
	public FamilyInfo(String address, int memberNum) {
		super();
		this.address = address;
		this.memberNum = memberNum;
	}
}

public class Employee {
	public String name;
	public FamilyInfo familyInfo;
	
	public Employee(String name, FamilyInfo familyInfo) {
		super();
		this.name = name;
		this.familyInfo = familyInfo;
	}
}

public class CloneTest {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		FamilyInfo familyInfoA=new FamilyInfo("No.1100 Lianhang Rd.",2);
		Employee employeeA=new Employee("Lily",familyInfoA);
		System.out.println("employeeA's address "+employeeA.familyInfo.address);
		Employee employeeB=employeeA;
		System.out.println("employeeB's address "+employeeB.familyInfo.address);
		System.out.println("---------------------");
		employeeA.familyInfo.address="No.1588 Pulian Rd.";
		System.out.println("employeeA's address "+employeeA.familyInfo.address);
		System.out.println("employeeB's address "+employeeB.familyInfo.address);	

	}
}

输出结果为:

        我们可以看到,随着employeeA对象 familyInfo值的改变,employeeB对象的值也受到影响。产生这种现象的原因是java中

Employee employeeB=employeeA;这条语句实际上是直接将对象employeeA的引用赋予employeeB,这样两个引用指向的是同一个对象。因此,当emploA对象改变的时候,employeeB的值也改变了。这就是浅拷贝。浅拷贝只拷贝对象引用本身,而不去拷贝引用的成员属性。从这个层次上来说,深clone并不是特别困难,简单地说,就是创建好对象,再设置一些成员属性。

       接下来看看java的clone技术是怎么实现深浅拷贝的。

     java中跟克隆有关的两个类分别是Cloneable接口和Object类中的clone方法,通过两者的协作来实现克隆。首先看一下java api doc中关于Cloneable接口和Object类中的clone方法的描述:

                      java.lang.Cloneable 接口,

          此类实现了 Cloneable 接口,以指示 Object.clone() 方法可以合法地对该类实例进行按字段复制。如果在没有实现 Cloneable 接口的实例上调用 Object 的 clone 方法,则会导致抛出 CloneNotSupportedException异常。 按照惯例,实现此接口的类应该使用公共方法重写 Object.clone(它是受保护的)。请参阅 Object.clone(),以获得有关重写此方法的详细信息。 

       Cloneable接口没有任何方法,仅是个标志接口(tagging interface),若要具有克隆能力,实现Cloneable接口的类必须重写从Object继承来的clone方法,并调用Object的clone方法,重写后的方法应为public 的。注意的是:java默认的clone()方法是浅拷贝,若要拷贝基本类型外加String类型以外的类型,即聚合或组合类间关系的时候,就需要进行深拷贝了。此时,常用的解决方法是纵深clone,即克隆到基本类型,外加String类型以外,不能再克隆为止。如下述例子:

public class FamilyInfo implements Cloneable{
	public String address;
	public int memberNum;
	
	public FamilyInfo(String address, int memberNum) {
		super();
		this.address = address;
		this.memberNum = memberNum;
	}
	
	public FamilyInfo clone(){
		FamilyInfo familyInfo=null;
		try {
			familyInfo=(FamilyInfo) super.clone();
		} catch (CloneNotSupportedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return familyInfo;
	}
}
public class Employee implements Cloneable{
	public String name;
	public FamilyInfo familyInfo;
	
	public Employee(String name, FamilyInfo familyInfo) {
		super();
		this.name = name;
		this.familyInfo = familyInfo;
	}
	
	public Employee clone(){
		Employee employee=null;
		try {
			employee=(Employee) super.clone();
			if(this.familyInfo!=null){
				employee.familyInfo=this.familyInfo.clone();
			}
		} catch (CloneNotSupportedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return employee;
		
	}
	
}

public class CloneTest {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		FamilyInfo familyInfoA=new FamilyInfo("No.1100 Lianhang Rd.",2);
		Employee employeeA=new Employee("Lily",familyInfoA);
		System.out.println("employeeA's address "+employeeA.familyInfo.address);
		Employee employeeB=employeeA.clone();
		System.out.println("employeeB's address "+employeeB.familyInfo.address);
		System.out.println("---------------------");
		employeeA.familyInfo.address="No.1588 Pulian Rd.";
		System.out.println("employeeA's address "+employeeA.familyInfo.address);
		System.out.println("employeeB's address "+employeeB.familyInfo.address);	

	}
}

输出结果为:


可以看到,深拷贝后,两个对象彼此独立,不受影响。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值