`

(转)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);	

	}
}

 

 

输出结果为:

 

 

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

分享到:
评论

相关推荐

    java-数组与方法及面向对象基础

    详细描述了java基础中的数组与方法的应用技术,以及面向对象的过程思想,有助于java初学者的入门学习。

    Java核心技术II(第8版)

    12.1 从Java程序中调用C函数 12.2 数值参数与返回值 12.2.1 用printf格式化数字 12.3 字符串参数 12.4 访问对象域 12.4.1 访问实例域 12.4.2 访问静态域 12.5 编码签名 12.6 调用Java方法 12.6.1 实例方法 12.6.2 ...

    java面试宝典

    42、一个“.java”源文件中是否可以包含多个类(不是内部类)?有什么限制? 12 43、说出一些常用的类,包,接口,请各举5 个。 12 44、Anonymous Inner Class (匿名内部类) 是否可以extends(继承)其它类?是否可以...

    java 面试题 总结

    它是基于Java的远程方法调用(RMI)技术的,所以EJB可以被远程访问(跨进程、跨计算机)。但EJB必须被布署在诸如Webspere、WebLogic这样的容器中,EJB客户从不直接访问真正的EJB组件,而是通过其容器访问。EJB容器是...

    Java面试宝典-经典

    1、一个".java"源文件中是否可以包括多个类(不是内部类)?有什么限制? 7 2、Java有没有goto? 7 3、说说&和&&的区别。 8 4、在JAVA中如何跳出当前的多重嵌套循环? 8 5、switch语句能否作用在byte上,能否作用在...

    Java面试宝典2010版

    1、一个".java"源文件中是否可以包括多个类(不是内部类)?有什么限制? 7 2、Java有没有goto? 7 3、说说&和&&的区别。 8 4、在JAVA中如何跳出当前的多重嵌套循环? 8 5、switch语句能否作用在byte上,能否作用在...

    java面试题大全(2012版)

    1、一个".java"源文件中是否可以包括多个类(不是内部类)?有什么限制? 7 2、Java有没有goto? 7 3、说说&和&&的区别。 8 4、在JAVA中如何跳出当前的多重嵌套循环? 8 5、switch语句能否作用在byte上,能否作用在...

    课程设计:基于java8+jsp+mysql+tomcat+javascript实现的在线考试系统【源码+数据库】.zip

    技术栈 java 8 + jsp + mysql + tomcat + javascript + css 相关工具组件 项目开发语言:java 8; Excel工具包:apache-poi 4.1.0; JSP标准标签库:jstl; 本地服务器:tomcat9.0; 数据库:mysql8; 启动 从git...

    最新Java面试宝典pdf版

    1、一个".java"源文件中是否可以包括多个类(不是内部类)?有什么限制? 7 2、Java有没有goto? 7 3、说说&和&&的区别。 8 4、在JAVA中如何跳出当前的多重嵌套循环? 8 5、switch语句能否作用在byte上,能否作用在...

    Java面试笔试资料大全

    1、一个".java"源文件中是否可以包括多个类(不是内部类)?有什么限制? 7 2、Java有没有goto? 7 3、说说&和&&的区别。 8 4、在JAVA中如何跳出当前的多重嵌套循环? 8 5、switch语句能否作用在byte上,能否作用在...

    java面试宝典2012

    1、一个".java"源文件中是否可以包括多个类(不是内部类)?有什么限制? 8 2、Java有没有goto? 8 3、说说&和&&的区别。 8 4、在JAVA中如何跳出当前的多重嵌套循环? 8 5、switch语句能否作用在byte上,能否作用在...

    java基础题 很全面

    53. 一个".java"源文件中是否可以包括多个类(不是内部类)?有什么限制? 13 54. java中有几种方法可以实现一个线程?用什么关键字修饰同步方法? stop()和suspend()方法为何不推荐使用? 13 55. java中有几种类型的流?...

    JAVA面试宝典2010

    1、一个".java"源文件中是否可以包括多个类(不是内部类)?有什么限制? 7 2、Java有没有goto? 8 3、说说&和&&的区别。 8 4、在JAVA中如何跳出当前的多重嵌套循环? 8 5、switch语句能否作用在byte上,能否作用在...

    Java面试宝典2012新版

    1、一个".java"源文件中是否可以包括多个类(不是内部类)?有什么限制? 7 2、Java有没有goto? 7 3、说说&和&&的区别。 8 4、在JAVA中如何跳出当前的多重嵌套循环? 8 5、switch语句能否作用在byte上,能否作用在...

    Java面试宝典2012版

    1、一个".java"源文件中是否可以包括多个类(不是内部类)?有什么限制? 7 2、Java有没有goto? 7 3、说说&和&&的区别。 8 4、在JAVA中如何跳出当前的多重嵌套循环? 8 5、switch语句能否作用在byte上,能否作用...

    一个修改Twitter的Java Web项目(基于重建的Servlet)

    git clone https://github.com/b2stry/mytwitter.git # 2.使用IDEA or Eclipse or STS导入本项目 # 3.新建数据库create database mytwitter; 导入数据库文件mytwitter.sql # 4.修改com/twitter/util/DBUtil.java中...

    chess-system-java

    it GitBash国际象棋系统 内容 关于 为了实践Java编程语言的基本使用而创建的项目。 具有在Udemy Course中开发的GitBash国际象棋游戏。 先决条件 在执行之前,您应该安装以下软件: ...技术领域 Java

Global site tag (gtag.js) - Google Analytics