`

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

	}
}

 

 

输出结果为:

 

 

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

分享到:
评论

相关推荐

    如何通过JVM角度谈谈Java的clone操作

    Java中的对象创建主要有两种方式,即使用`new`操作符创建新对象以及通过`clone`方法...在实际编程中,还可以考虑使用其他技术,如拷贝构造函数或工厂方法,来替代或补充`clone`操作,以实现更安全、更可控的对象复制。

    关于java clone的一些基本的概念

    在Java中实现深拷贝通常需要自定义`clone`方法或者使用序列化和反序列化技术。 对于`Cloneable`接口,当一个类需要支持`clone`操作时,应当实现这个接口。不过要注意的是,`Cloneable`接口本身没有任何方法,只是一...

    Java clone方法详解及简单实例

    Java中的`clone`方法是Java语言提供的一种复制对象的机制,它允许创建一个现有对象的副本,这个副本具有与原始对象相同的状态,但它们是独立的实体,对其中一个对象的修改不会影响另一个。`clone`方法是Java `Object...

    java web 前台技术

    Java Web前台技术是Web应用程序开发中的重要组成部分,主要关注用户界面的设计、交互和用户体验。这份“Java Web前台技术”资料集全面涵盖了与之相关的多个关键知识点,旨在帮助开发者提升技能和效率。 一、HTML...

    JAVA_高级特性(hashCode,clone,比较器,Class反射,序列化)

    ### Java 高级特性详解 #### 一、`hashCode` ...正确地重写 `equals` 和 `hashCode` 方法、使用 `Comparator` 进行排序、利用反射机制和序列化技术,以及实现 `clone` 方法都是开发高质量 Java 应用程序的重要技能。

    Java技术要点与面试经典2013版

    以下是一些关键的Java知识点,源自《Java技术要点与面试经典2013版》的部分内容: 1. 一个".java"源文件可以包含多个类,但只能有一个公开类(public class),其他类可以是非公开的(如private或默认包访问)。...

    详解java中的深拷贝和浅拷贝(clone()方法的重写、使用序列化实现真正的深拷贝)

    在Java中,浅拷贝可以通过实现`Cloneable`接口并重写`clone()`方法来完成。以下是一个简单的浅拷贝示例: ```java public class Person implements Cloneable { private String name; private int age; private ...

    干货!资深java工程师面试要点大全+一年整理.pdf

    这是Java语言继承体系的基础,所有的类都继承自Object类,这意味着Object类中的方法在Java的任何对象中都可用,比如equals()、hashCode()、toString()、clone()等。clone()方法是一个特殊的对象复制方法,实现浅克隆...

    Java面试宝典2013最新版

    7. Java的clone()方法在实现时,通常会有一行代码是调用super.clone()。 8. 面向对象编程的三大特性:封装、继承、多态,是Java语言的核心知识点。 9. Java中的多态实现机制是通过方法重载(Overloading)和方法...

    java高端技术课程--Java数组如何实现复制

    在Java编程语言中,数组是一种基础且重要的数据结构,它用于存储同类型的多个元素。数组复制是编程中常见的操作,特别是在处理数据时需要备份或移动数据的场景。本篇文章将深入探讨Java中数组的复制方法及其相关知识...

    Java面试指南.pdf

    Java面试的准备可以分为几个部分,其中最重要的部分是Java技术相关,包括了Java的基础知识、核心API的解读以及Java中高级技术的理解。同时,面试者应该熟悉应聘流程,了解如何撰写简历,以及在面试中如何谈论福利...

    Java面试宝典2018-最全面试资料

    此外,书中还涉及了对象克隆(clone)的概念,这是Java中实现对象深度复制的技术。 Java SE语法是程序员必须掌握的基础,包括Java语言中的关键字和特殊符号的使用,例如“&”和“&&”的区别、goto语句的不存在、...

    clone

    虚拟机克隆是虚拟化技术中的一个重要特性,它允许从一个运行的或停止的虚拟机创建一个完全一样的新虚拟机。 6. **数据备份和恢复** 在数据备份领域,克隆也扮演着关键角色。通过克隆,用户可以创建一个与原始数据...

    java的设计模式 《设计模式-java语言中的应用.pdf》

    Java中的`Cloneable`接口和`Object`类的`clone()`方法支持原型模式的实现。 6. **适配器模式**:将一个类的接口转换成客户希望的另一个接口。在Java中,可以使用类适配器或接口适配器,使不兼容的接口能够协同工作...

    JAVA版数据结构.pdf

    文档中提到了在`clone()`方法中的异常处理,这表明文档可能涉及Java中的异常处理机制,包括`try`、`catch`、`finally`和`throw`关键字的使用。 11. Java类的继承和接口 文档提到了`implements`关键字,这涉及到Java...

    JAVA面试宝典.pdf

    《JAVA面试宝典》是一本全面涵盖Java技术体系和求职面试知识的指南,旨在帮助Java开发者准备面试,提升技能。本书共分为十章,从基础知识到框架应用,再到项目实战和面试题解析,覆盖了Java开发者的必备技能。 第一...

    Java的23种设计模式百度云下载链接.rar

    Java中提供了`clone()`方法支持浅复制。 6. **组合模式**:允许你将对象组合成树形结构来表现“整体/部分”层次结构。在Java UI组件树中广泛应用。 7. **装饰器模式**:动态地给一个对象添加一些额外的职责。Java...

    grpc-java源码环境构建.doc

    GRPC-Java 源码环境构建是一个相对复杂的过程,需要具备一定的技术基础和经验。本文将详细介绍 GRPC-Java 源码环境构建的步骤和过程,旨在帮助读者快速搭建 GRPC-Java 源码环境。 一、Clone GRPC-Java 源码 GRPC-...

Global site tag (gtag.js) - Google Analytics