深复制和浅复制

时间:2022-08-23 14:35:31

在设计模式中的prototype模式中,要特别留意的是其中的深复制和浅复制,现在小结一下

1 浅复制
   当进行浅复制时,如果类中包含了子对象,当这个类的包含的子引用对象发生改变时,这个变化会同时出现在它的浅复制克隆的对象中
去,比如
public class Lay1 implements Cloneable {
 public int x;
 public Lay2 lay2;
 public Object clone()
 {
  Object clone=null;
  try
  {
   
   clone=super.clone();
  }
  catch (CloneNotSupportedException e)
  {
   
  }
  return clone;
 }

}

Lay1中包含子对象lay2了,lay2指向一个类Lay2
public class Lay2 implements Cloneable {
 public int y;
 public Object clone()
 {
  Object clone=null;
  try
  {
   clone=super.clone();
  }
  catch (CloneNotSupportedException e)
  {
   
  }
  return clone;
   }

}
客户程序
public class Client {
   public static  void main(String argv[])
   {
     Lay1 obj1=new Lay1();
     obj1.lay2=new Lay2();
     obj1.x=1;
     obj1.lay2.y=1;
     Lay1 obj2=(Lay1)obj1.clone();
     obj2.x=2;
     obj2.lay2.y=2;
     System.out.println("obj1.x is:"+obj1.x+"/tObj1.lay2.y is:"+obj1.lay2.y);
     System.out.println("obj2.x is:"+obj2.x+"/tObj2.lay2.y is:"+obj2.lay2.y);
   }
 }

输出为
obj1.x i s:1  obj1.lay2.y=2
obj2.x  is 2  obj2.lay2.y=
可以看到 obj1当前层的对象别clone了一份,但clone对象的值的改变不反映到父对象,但修改其引用的子对象lay2的值,会反映到父方,因为大家都是指向同一个地方嘛。

为了深复制,可以这样做
public class Lay1 implements Cloneable {
   public int x;
   public Lay2 lay2;
   public Object clone() {
   
    Lay1 temp=null;
     try {
     
      temp=(Lay1)super.clone();
      temp.lay2=(Lay2)lay2.clone();
     }
     catch (CloneNotSupportedException e) {
       // should never happen
     }

     return temp;
   }
 }

public class Lay2 implements Cloneable {
   public int y;
   public Object clone() {
     Object clone = null;
     try {
       clone = super.clone ();
     }
     catch (CloneNotSupportedException e) {
       // should never happen
     }
     return clone;
   }
 }

public class Client {
   public static  void main(String argv[])
   {
     Lay1 obj1=new Lay1();
     obj1.lay2=new Lay2();
     obj1.x=1;
     obj1.lay2.y=1;
     Lay1 obj2=(Lay1)obj1.clone();
     obj2.x=2;
     obj2.lay2.y=2;
     System.out.println("obj1.x is:"+obj1.x+"/tObj1.lay2.y is:"+obj1.lay2.y);
     System.out.println("obj2.x is:"+obj2.x+"/tObj2.lay2.y is:"+obj2.lay2.y);
   }
 
可以看到。输出是
obj1.x is:1 Obj1.lay2.y is:1
obj2.x is:2 Obj2.lay2.y is:2

另外,给出C#版本的代码,注意C#中浅复制用到的memberwiseclone()(转自
http://www.cnblogs.com/zhenyulu/articles/39257.aspx
using System;
深复制和浅复制
深复制和浅复制
class ShallowCopy : ICloneable
深复制和浅复制深复制和浅复制
{
深复制和浅复制深复制和浅复制  
public int[] v = {1,2,3};
深复制和浅复制
深复制和浅复制  
public Object Clone()
深复制和浅复制深复制和浅复制  
{
深复制和浅复制    
return this.MemberwiseClone();
深复制和浅复制  }

深复制和浅复制
深复制和浅复制  
public void Display()
深复制和浅复制深复制和浅复制  
{
深复制和浅复制    
foreach(int i in v)
深复制和浅复制      Console.Write( i 
+ "");
深复制和浅复制    Console.WriteLine();
深复制和浅复制  }

深复制和浅复制}

深复制和浅复制
深复制和浅复制
class Client
深复制和浅复制深复制和浅复制
{
深复制和浅复制  
public static void Main()
深复制和浅复制深复制和浅复制  
{
深复制和浅复制    ShallowCopy sc1 
= new ShallowCopy();
深复制和浅复制    ShallowCopy sc2 
= (ShallowCopy)sc1.Clone();
深复制和浅复制    sc1.v[
0= 9;
深复制和浅复制
深复制和浅复制    sc1.Display();
深复制和浅复制    sc2.Display();
深复制和浅复制  }

深复制和浅复制}


ShallowCopy对象实现了一个浅拷贝,因此当对sc1进行克隆时,其字段v并没有克隆,这导致sc1与sc2的字段v都指向了同一个v,因此,当修改了sc1的v[0]后,sc2的v[0]也发生了变化。

深复制
using System;
深复制和浅复制
深复制和浅复制
class DeepCopy : ICloneable
深复制和浅复制深复制和浅复制
{
深复制和浅复制深复制和浅复制  
public int[] v = {1,2,3};
深复制和浅复制
深复制和浅复制  
// 默认构造函数
深复制和浅复制
  public DeepCopy()
深复制和浅复制深复制和浅复制  
{
深复制和浅复制  }

深复制和浅复制
深复制和浅复制  
// 供Clone方法调用的私有构造函数
深复制和浅复制
  private DeepCopy(int[] v)
深复制和浅复制深复制和浅复制  
{
深复制和浅复制    
this.v = (int[])v.Clone();
深复制和浅复制  }

深复制和浅复制
深复制和浅复制  
public Object Clone()
深复制和浅复制深复制和浅复制  
{
深复制和浅复制    
// 构造一个新的DeepCopy对象,构造参数为
深复制和浅复制    
// 原有对象中使用的 v 
深复制和浅复制
    return new DeepCopy(this.v);
深复制和浅复制  }

深复制和浅复制
深复制和浅复制  
public void Display()
深复制和浅复制深复制和浅复制  
{
深复制和浅复制    
foreach(int i in v)
深复制和浅复制      Console.Write( i 
+ "");
深复制和浅复制    Console.WriteLine();
深复制和浅复制  }

深复制和浅复制}

深复制和浅复制
深复制和浅复制
class Client
深复制和浅复制深复制和浅复制
{
深复制和浅复制  
public static void Main()
深复制和浅复制深复制和浅复制  
{
深复制和浅复制    DeepCopy dc1 
= new DeepCopy();
深复制和浅复制    DeepCopy dc2 
= (DeepCopy)dc1.Clone();
深复制和浅复制    dc1.v[
0= 9;
深复制和浅复制
深复制和浅复制    dc1.Display();
深复制和浅复制    dc2.Display();
深复制和浅复制  }

深复制和浅复制}


这次在克隆的时候,不但克隆对象本身,连里面的数组字段一并克隆。因此,最终打印出来的dc1与dc2不同。