克隆当将一个引用变量赋值绐另外一个引用变量时,只是简单地创建了指向同一个对象的第二个引用。如果要制造一个对象的副本,你就需要某种机制来创建同一个类的新实例,并且基于原来对象的状态初始化该实例。Object.MemberwiseClone方法就是做这件事情的;然而,它不是一个公有办法。更进一步说,如果对象要想支持克隆( cloning),往往需要实现System.ICloneable接口,该接口有一个方法Clone:
namespace System {
public
interface ICloneable
{
Object Clone() ;
}
MemberwiseClone方法执行的是浅表副本(shallow copy),这意味着它只是将原对象的每个字段的值拷贝到克隆体中。如果字段是一个对象引用,那么,拷贝的仅仅是这个引用.而不是引用的对象。下面的类使用
浅表副本实现了ICloneable接口:
Pulic sealed class Marriage:System.ICloneable{
Internal Person g;
Internal Person b;
Public Object Clone(){
Return this.MemberwiseClone();
}
}
图5.9是浅表副本的结果。
深层副本(deep copy)是指递归拷贝其字段所引用的所有对象,如图5.10所示。深层副本经常是人们所期望的;但它不是默认的行为,并且在一般情形下实现深层副本也不是好主意。深层副本除了会引起额外的内存活动和资源消耗之外,当对象层次结构( a graph of objects)出现环路时,深层副本还会出现问题,其原因是递归有可能陷入无限循环。不过,对于简单的对象层次结构,它全少是可以实现的,如下例5.8所示。
示例5.8 实现System.ICloneable接口
Public sealed class Marriage:System.ICloneable{
Internal Person g;
Internal Person b;
Public Object Clone(){
//首先进行浅拷贝
Marriage result=(Marriage)this.MemberwiseClone();
//深拷贝每个字段
Result.g=(Person){this.g.Clone()};
Result.b=(Person){this.b.Clone()};
Return result;
}
}
在示例5.8中,Clone的实现居然可以不调用MemberwisClone方法。一个可供选择的实现就是简单地使用new操作符实例化第二个对象,并且手动产生它的字段。此外你还可以定义一个私有构造函数,使这两个部分(实例化和初始化)合并成一步。示例5.9就是这样一种实现。
示例5.9 使用关键字new实现System.ICloneable接口
Public sealed class Marriage:System.ICloneable{
Internal Person g;
Internal Person b;
Private Marriage(Person g,Person b){
This.g=(Person)g.Clone();
This.b=(Person)b.Clone();
}
Public Object Clone(){
Return new Marriage(g,b)
}
}