您的位置:首页 > 编程语言 > Java开发

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)。先看一个与浅拷贝相关的代码段:

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

}
}


输出结果为:



可以看到,深拷贝后,两个对象彼此独立,不受影响。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: