Clone
Cloneable
接口
如果直接把一个变量赋给另一个变量,例如下面这句,e1,e2将指向同一个引用对象,如果改变e2的值,e1的值同样将被改变。
Employee e2 = e1;
因此,为了使e1,e2可以各自改变状态,需要使用clone方法。clone()完全创造出一个新的对象,有自己的新的地址,只不过初始信息是和原对象是一样的。
public Employee clone() throws CloneNotSupportedException
{
// call Object.clone()
Employee cloned = (Employee) super.clone();
// clone mutable fields
cloned.hireDay = (Date) hireDay.clone();
return cloned;
}
Cloneable接口是空的,不包括任何常量和抽象方法。实现Cloneable接口的类标记为可克隆的,这个类必须覆盖在Object类中定义的clone( )方法。
Object中的源码:
protected native Object clone() throws CloneNotSupportedException;
浅拷贝
如果对象中的所有数据域都是数值或基本类型,使用clone拷贝域没有任何问题。但如果在对象中包含了子对象的引用,clone不会拷贝子对象,只是把两个域引用同一个子对象。
比如说,我们上面说到的Employee,它有一个string域、一个Date域。String域不允许改变的类,拷贝不会出错。但Date类是可变的子对象,直接拷贝会出错!因此必须重新定义clone方法
对每一个类,我们要先做出以下判断:
- 默认的clone方法是否满足要求
- 默认的clone方法是否能够通过调用可变子对象的clone得到修补。
- 是否不应该使用clone
深拷贝
深拷贝和浅拷贝正好相反,在克隆一个对象时,其内的引用也发生了相应的克隆,都会产生完全没有关联的对象。即在对象中包含了子对象的引用,clone也会拷贝子对象。
public EmployeeForClone clone() throws CloneNotSupportedException
{
// call Object.clone()
EmployeeForClone cloned = (EmployeeForClone) super.clone();
// clone mutable fields
cloned.hireDay = (Date) hireDay.clone();
return cloned;
}
hireDay就是我们上边说的Date对象,重新修改代码后实现了深拷贝。
只要在clone中含有没有实现Cloneable接口的对象,Object类的clone方法就会抛出一个CloneNot-SupportException
异常。因此需要声明 ... throws CloneNotSupportedException