java深克隆和浅克隆

克隆就是复制一个对象的复本.但一个对象中可能有基本数据类型,如:int,long,float    等,也同时含有非基本数据类型如(数组,集合等)
被克隆得到的对象基本类型的值修改了,原对象的值不会改变.这种适合shadow clone(浅克隆).

但如果你要改变一个非基本类型的值时,原对象的值却改变了,.比如一个数组,内存中只copy他的地址,而这个地址指向的值并没有copy,当clone时,两个地址指向了一个值,这样一旦这个值改变了,原来的值当然也变了,因为他们共用一个值.,这就必须得用深克隆(deep clone)

以下举个例子,说明以上情况:

被克隆类:ShadowClone.java

class  ShallowClone  implements  Cloneable {
    
public   int  a;
    
public   int [] b;
    
    
public  ShallowClone() {
        a 
=   5 ;
        b 
=   new   int [] { 1 2 3 4 5 };
    }
    
    
//  浅克隆,对于克隆后的对象,只能保证对基础类型成员的修改不会影响原对象的相应成员
    
//  对类类型和数组类型的成员,只是拷贝了对象的地址,因此对克隆后对象的这些类型成员
    
//  进行修改会影响原对象
    @Override
    
public  Object clone() {
        ShallowClone sc 
=   null ;
        
try  {
            sc 
=  (ShallowClone) super .clone();
        } 
catch  (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        
return  sc;
    }
}

测试类:

public   class  DeepAndShallowClone {
    
public   static   void  main(String[] args)  throws  Exception {
        
//  shallow clone
        ShallowClone sc  =   new  ShallowClone();
        ShallowClone scCopy 
=  (ShallowClone)sc.clone();
        
        
        System.out.println(
" Shallow Copy " );
        System.out.println(
" --Before clone " );
        System.out.println(
" sc.a= "   +  sc.a);
        System.out.println(
" sc.b= "   +  sc.b[ 0 ]);
        
        scCopy.a 
=   1 ;
        scCopy.b[
0 =   10 ;
        System.out.println(
" --After clone " );
        System.out.println(
" sc.a= "   +  sc.a);
        System.out.println(
" sc.b= "   +  sc.b[ 0 ]);
        System.out.println(
" scCopy.a= "   +  scCopy.a);
        System.out.println(
" scCopy.b= "   +  scCopy.b[ 0 ]);
    }
}

结果如下:

Shallow Copy
-- Before clone
sc.a
= 5
sc.b
= 1
-- After clone
sc.a
= 5
sc.b
= 10
scCopy.a
= 1
scCopy.b
= 10

问题出现了,修改了克隆后的对象scCopy.b[0]的值,但sc.b[0]的值也改变了,与scCopy.b[0]的值相等.
以下针对浅克隆得出结论:基本类型是可以被克隆的,但引用类型只是copy地址,并没有copy这个地址指向的对象的值,这使得两个地址指向同一值,修改其中一个,当然另一个也就变了.
由此可见,浅克隆只适合克隆基本类型,对于引用类型就不能实现克隆了.

那如何实现克隆引用对象呢,以下提供一种方法.    用序列化与反序列化实现深克隆(deep copy)

被克隆对象.DeepClone.java

class  DeepClone  implements  Serializable {
    
private   static   final   long  serialVersionUID  =   1L ;
    
public   int  a;
    
public   int [] b;
    
    
public  DeepClone() {
        a 
=   10 ;
        b 
=   new   int [] { 6 7 8 9 10 };
    }
    
    
//  使用ObjectInput(Output)Stream和ByteArrayInput(Output)Stream实现深克隆
     public  Object deepClone()  throws  IOException, ClassNotFoundException {
        DeepClone dc 
=   null ;
        ByteArrayOutputStream baos 
=   new  ByteArrayOutputStream();
        ObjectOutputStream oos 
=   new  ObjectOutputStream(baos);
        oos.writeObject(
this );
        oos.close();
        
        ByteArrayInputStream bais 
=   new  ByteArrayInputStream(baos.toByteArray());
        ObjectInputStream bis 
=   new  ObjectInputStream(bais);
        dc 
=  (DeepClone)bis.readObject();
        
return  dc;
    }
}

  测试类:

public   class  DeepAndShallowClone {
    
public   static   void  main(String[] args)  throws  Exception {
        DeepClone dc 
=   new  DeepClone();
        DeepClone dcCopy 
=  (DeepClone)dc.deepClone();
        System.out.println(
" --Before clone " );
        System.out.println(
" dc.a= "   +  dc.a);
        System.out.println(
" dc.b= "   +  dc.b[ 0 ]);
        dcCopy.a 
=   1 ;
        dcCopy.b[
0 =   1 ;
        
        System.out.println(
" Shallow Copy " );
        System.out.println(
" --After clone " );
        System.out.println(
" dc.a= "   +  dc.a);
        System.out.println(
" dc.b= "   +  dc.b[ 0 ]);
        System.out.println(
" dcCopy.a= "   +  dcCopy.a);
        System.out.println(
" dcCopy.b= "   +  dcCopy.b[ 0 ]);
    }
}

  结果如下:

-- Before clone
dc.a
= 10
dc.b
= 6
Shallow Copy
-- After clone
dc.a
= 10
dc.b
= 6
dcCopy.a
= 1
dcCopy.b
= 1

writeObject方法会将被克隆类的对象关系网都写出,这样就可以实现深克隆。当然,每个被克隆的成员类型必须实现Serializable接口

你可能感兴趣的:(java)