1.为什么要克隆?

假如有一个Person类,通常的做法是进行赋值,如Person p2=p1,这个时候只是简单了copy了一下reference,p1和p2都指向内存中同一个object,这样p1或者p2的一个操作都可能影响到对方。比如在p2中对Person中的某个参数进行了修改,P1所中的相应参数也会有所改动,这显然是我们不愿意看到的。如果要做到互不影响,我们希望得到p2的一个精确拷贝,同时两者互不影响,这时候我们就可以使用Clone来满足我们的需求。Person p2=tp1.clone(),这时会生成一个新的Person 对象,并且和p1具有相同的属性值和方法。

2.浅度克隆(shadow clone)&深度克隆(deep clone)

Clone是如何完成的呢?Object在对某个对象实施Clone时对其是一无所知的,它仅仅
是简单地执行域对域的copy,这就是Shallow Clone。这样,问题就来了咯,以Employee为例,它里面有一个域hireDay不是基本型别的变量,而是一个reference变量,经过Clone之后就会产生一个新的Date型别的reference,它和原始对象中对应的域指向同一个Date对象,这样克隆类就和原始类共享了一部分信息,而这样显然是不利的,过程下图所示:
Cloneable接口
这个时候我们就需要进行deep Clone了,对那些非基本型别的域进行特殊的处理,例如本例中的hireDay。我们可以重新定义Clone方法,对hireDay做特殊处理,如下代码所示:
 Cloneable
{
            public Object clone() throws CloneNotSupportedException
            {
             Employee cloned 
= (Employee) super.clone();
        cloned.hireDay 
= (Date) hireDay.clone()
        
return cloned;
            }
3. Clone()方法的保护机制
在Object中Clone()是被申明为protected的,这样做是有一定的道理的,以Employee
类为例,通过申明为protected,就可以保证只有Employee类里面才能“克隆”Employee对象4. Clone()方法的使用
Clone()方法的使用比较简单,注意如下几点即可:
a. 什么时候使用shallow Clone,什么时候使用deep Clone,这个主要看具体对象的域是什么性质的,基本型别还是reference variable

b. 调用Clone()方法的对象所属的类(Class)必须implements Clonable接口,否则在调用Clone方法的时候会抛出CloneNotSupportedException。

下面讲举一个clone的例子:

 Cloneable {
   int age;
   String name;

public Friend(int age, String name) {
   
this.age = age;
   
this.name = name; 
}

public Object clone () throws CloneNotSupportedException {
   
return super.clone(); 
}
   
}

class Person implements Cloneable {
   
int age;
/* *
   *String 类型特殊,因为他为引用型,而且他指向的值为常量,克隆出来的对象改变他的
   *值实际上是改变了克隆出来对象String类型成员的指向不会影响被克隆对象的值及其指向?
   *因为引用被克隆了,我改变的是引用的指向!
*/
   String name;

   Friend f;

public Person(int age, String name, Friend f) {
   
this.age = age;
   
this.name = name;
   
this.f = f;
}

public Object clone () throws CloneNotSupportedException {
   Person p 
= (Person)super.clone();
   p.f 
= (Friend)p.f.clone();
   
return p; 
}

public String toString(){
StringBuffer sb 
= new StringBuffer();
return super.toString()+sb.append("age=").append(age).
   append(
",name=").append(name).
   append(
"friend=").append("f.name=").
   append(f.name).append(
"f.age=").append(f.age).toString();
}
}


public class Clonetest {
public static void main(String [] args) throws CloneNotSupportedException {
   Person p 
= new Person(4,"haha",new Friend(5,"hehe"));
   Person p1 
= (Person)p.clone();
   p1.name 
= "oop";
   p1.age 
= 10;
   p1.f.name 
= "ooad";
   p1.f.age 
= 56;
   System.out.println (p);
System.out.println (p1);

输出结果为:

---------- java ----------
Person@d9f9c3age=4,name=hahafriend=f.name=hehef.age=5
Person@9cab16age=10,name=oopfriend=f.name=ooadf.age=56
Normal Termination
输出完成(耗时 1 秒)。

此程序中的输出不知道为什么会是这样,后来查了资料发现是和toString有关。下篇将总结一下toString的用法。

这篇文章我是没有耐心看了,不过最近又看了一下浅度拷贝和深度拷贝,可以这样来说吧,举例子子,有一个Book类,里面有三个属性String bname,double price,Person author。发现了吧,这里面的author是另一个Person类。Book有创建了两个实例,b1和b2。当执行b2=b1.clone()后,更改了b2中author的属性值,你会发现b1中author的属性值也会改变,为什么呢?因为这是浅拷贝,要在override的clonable()方法里把Person方法一起拷贝,这样,即使改变了b2中author的属性值了b1中author的属性值也不会改变,这就是深度拷贝了。例子不写了,呵呵(写给自己看的,对不住了)

相关文章: