java中的clone技术
2012-07-04 20:17
197 查看
编程过程中常常遇到如下情况: 假设有一个对象obj1,在某处需要和obj1一样的实例obj2,强调obj1和obj2是两个独立的实例,只是在开始的时候,它们具有一样的属性。这种情况下,一般的一种解决方法是:重新new一个对象obj2,然后将obj1的属性字段值依次赋予obj2。该种方法可行,但是也比较土。java提供了clone方法,使用clone方法,我们可以高效地解决上述的问题。
在理解clone方法前,有必要先了解下浅拷贝(shallow copy)和深拷贝(deep copy)。先看一个与浅拷贝相关的代码段:
输出结果为:
我们可以看到,随着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类型以外,不能再克隆为止。如下述例子:
输出结果为:
可以看到,深拷贝后,两个对象彼此独立,不受影响。
在理解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); } }
输出结果为:
可以看到,深拷贝后,两个对象彼此独立,不受影响。
相关文章推荐
- java clone技术 浅谈 转
- java clone技术 浅谈
- Java克隆(clone)技术浅析
- 11. JAVA常用类库 Part 4 (对象克隆技术clone、Arrays类、Comparable接口、比较器Comparator、观察者设计模式) ----- 学习笔记
- 深入浅出Java clone技术
- 深入浅出Java clone技术(1)
- 深入浅出Java clone技术
- java的对象克隆技术clone()之浅度克隆(shallow Clone)
- 深入浅出Java clone技术(2)
- Java常用类库--对象克隆技术clone
- 深入浅出Java clone技术
- java clone技术 浅谈
- 深入浅出Java clone技术
- 深入浅出Java clone技术(3)
- 带你揭开Java clone技术的神秘面纱-Java基础-Java-编程开发
- 深入浅出 Java clone 技术
- 深入浅出Java clone技术
- .Net/C#/VB/T-SQL/Java/Script 实现: 将天文数字转换成中文大写 (2000 年前的思路,打劫的,一点儿技术含量都没有)
- 整合PDF和Java技术
- Java开发技术十年的回顾与展望