(转)java中的clone技术

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

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

 

  1. public class FamilyInfo {  
  2.     public String address;  
  3.     public int memberNum;  
  4.       
  5.     public FamilyInfo(String address, int memberNum) {  
  6.         super();  
  7.         this.address = address;  
  8.         this.memberNum = memberNum;  
  9.     }  
  10. }  
public class FamilyInfo {
	public String address;
	public int memberNum;
	
	public FamilyInfo(String address, int memberNum) {
		super();
		this.address = address;
		this.memberNum = memberNum;
	}
}

 

  1. public class Employee {  
  2.     public String name;  
  3.     public FamilyInfo familyInfo;  
  4.       
  5.     public Employee(String name, FamilyInfo familyInfo) {  
  6.         super();  
  7.         this.name = name;  
  8.         this.familyInfo = familyInfo;  
  9.     }  
  10. }  
public class Employee {
	public String name;
	public FamilyInfo familyInfo;
	
	public Employee(String name, FamilyInfo familyInfo) {
		super();
		this.name = name;
		this.familyInfo = familyInfo;
	}
}

 

  1. public class CloneTest {  
  2.   
  3.     /** 
  4.      * @param args 
  5.      */  
  6.     public static void main(String[] args) {  
  7.         // TODO Auto-generated method stub   
  8.         FamilyInfo familyInfoA=new FamilyInfo("No.1100 Lianhang Rd.",2);  
  9.         Employee employeeA=new Employee("Lily",familyInfoA);  
  10.         System.out.println("employeeA's address "+employeeA.familyInfo.address);  
  11.         Employee employeeB=employeeA;  
  12.         System.out.println("employeeB's address "+employeeB.familyInfo.address);  
  13.         System.out.println("---------------------");  
  14.         employeeA.familyInfo.address="No.1588 Pulian Rd.";  
  15.         System.out.println("employeeA's address "+employeeA.familyInfo.address);  
  16.         System.out.println("employeeB's address "+employeeB.familyInfo.address);      
  17.   
  18.     }  
  19. }  
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类型以外,不能再克隆为止。如下述例子:

 

  1. public class FamilyInfo implements Cloneable{  
  2.     public String address;  
  3.     public int memberNum;  
  4.       
  5.     public FamilyInfo(String address, int memberNum) {  
  6.         super();  
  7.         this.address = address;  
  8.         this.memberNum = memberNum;  
  9.     }  
  10.       
  11.     public FamilyInfo clone(){  
  12.         FamilyInfo familyInfo=null;  
  13.         try {  
  14.             familyInfo=(FamilyInfo) super.clone();  
  15.         } catch (CloneNotSupportedException e) {  
  16.             // TODO Auto-generated catch block   
  17.             e.printStackTrace();  
  18.         }  
  19.         return familyInfo;  
  20.     }  
  21. }  
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;
	}
}
  1. public class Employee implements Cloneable{  
  2.     public String name;  
  3.     public FamilyInfo familyInfo;  
  4.       
  5.     public Employee(String name, FamilyInfo familyInfo) {  
  6.         super();  
  7.         this.name = name;  
  8.         this.familyInfo = familyInfo;  
  9.     }  
  10.       
  11.     public Employee clone(){  
  12.         Employee employee=null;  
  13.         try {  
  14.             employee=(Employee) super.clone();  
  15.             if(this.familyInfo!=null){  
  16.                 employee.familyInfo=this.familyInfo.clone();  
  17.             }  
  18.         } catch (CloneNotSupportedException e) {  
  19.             // TODO Auto-generated catch block   
  20.             e.printStackTrace();  
  21.         }  
  22.         return employee;  
  23.           
  24.     }  
  25.       
  26. }  
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;
		
	}
	
}

 

  1. public class CloneTest {  
  2.   
  3.     /** 
  4.      * @param args 
  5.      */  
  6.     public static void main(String[] args) {  
  7.         // TODO Auto-generated method stub   
  8.         FamilyInfo familyInfoA=new FamilyInfo("No.1100 Lianhang Rd.",2);  
  9.         Employee employeeA=new Employee("Lily",familyInfoA);  
  10.         System.out.println("employeeA's address "+employeeA.familyInfo.address);  
  11.         Employee employeeB=employeeA.clone();  
  12.         System.out.println("employeeB's address "+employeeB.familyInfo.address);  
  13.         System.out.println("---------------------");  
  14.         employeeA.familyInfo.address="No.1588 Pulian Rd.";  
  15.         System.out.println("employeeA's address "+employeeA.familyInfo.address);  
  16.         System.out.println("employeeB's address "+employeeB.familyInfo.address);      
  17.   
  18.     }  
  19. }  
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、付费专栏及课程。

余额充值