深度复制和浅复制的区别是什么?


当前回答

浅拷贝不会创建新的引用,但深拷贝会创建新的引用。

下面是程序解释的深拷贝和浅拷贝。

public class DeepAndShollowCopy {
    int id;
    String name;
    List<String> testlist = new ArrayList<>();

    /*
    // To performing Shallow Copy 
    // Note: Here we are not creating any references. 
      public DeepAndShollowCopy(int id, String name, List<String>testlist)
       { 

       System.out.println("Shallow Copy for Object initialization");
       this.id = id; 
       this.name = name; 
       this.testlist = testlist; 

       }
    */  

    // To performing Deep Copy 
    // Note: Here we are creating one references( Al arraylist object ). 
    public DeepAndShollowCopy(int id, String name, List<String> testlist) {
        System.out.println("Deep Copy for Object initialization");
        this.id = id;
        this.name = name;
        String item;
        List<String> Al = new ArrayList<>();
        Iterator<String> itr = testlist.iterator();
        while (itr.hasNext()) {
            item = itr.next();
            Al.add(item);
        }
        this.testlist = Al;
    }


    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("Java");
        list.add("Oracle");
        list.add("C++");
        DeepAndShollowCopy copy=new DeepAndShollowCopy(10,"Testing", list);
        System.out.println(copy.toString());
    }
    @Override
    public String toString() {
        return "DeepAndShollowCopy [id=" + id + ", name=" + name + ", testlist=" + testlist + "]";
    }
}

其他回答

复制array:

Array是一个类,这意味着它是引用类型,因此array1 = array2的结果 在引用同一个数组的两个变量中。

但是看看这个例子:

  static void Main()
    {
        int[] arr1 = new int[] { 1, 2, 3, 4, 5 }; 
        int[] arr2 = new int[] { 6, 7, 8, 9, 0 };

        Console.WriteLine(arr1[2] + " " + arr2[2]);
        arr2 = arr1;
        Console.WriteLine(arr1[2] + " " + arr2[2]); 
        arr2 = (int[])arr1.Clone();
        arr1[2] = 12;
        Console.WriteLine(arr1[2] + " " + arr2[2]);
    }

浅克隆意味着只复制克隆数组所表示的内存。

如果数组包含值类型对象,则复制值;

如果数组包含引用类型,则只复制引用-因此有两个数组,其成员引用相同的对象。

要创建复制引用类型的深度复制,必须循环遍历数组并手动克隆每个元素。

浅复制-原始和浅复制对象中的引用变量引用公共对象。

深度复制-原始和深度复制对象中的引用变量引用不同的对象。

克隆总是做浅拷贝。

public class Language implements Cloneable{
    
    String name;
    public Language(String name){
        this.name=name;
    }
    
    public String getName() {
        return name;
    }
    
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

主类如下-

public static void main(String args[]) throws ClassNotFoundException, CloneNotSupportedException{

      ArrayList<Language> list=new ArrayList<Language>();
      list.add(new Language("C"));
      list.add(new Language("JAVA"));

      ArrayList<Language> shallow=(ArrayList<Language>) list.clone();
      //We used here clone since this always shallow copied.

      System.out.println(list==shallow);
      
      for(int i=0;i<list.size();i++)
      System.out.println(list.get(i)==shallow.get(i));//true
      
      ArrayList<Language> deep=new ArrayList<Language>();
      for(Language language:list){
          deep.add((Language) language.clone());
      }
      System.out.println(list==deep);
      for(int i=0;i<list.size();i++)
          System.out.println(list.get(i)==deep.get(i));//false
      
} 

以上输出为-

假真假真 假假假

原始物体的任何变化都将反映在浅物体上,而不是在深物体上。

  list.get(0).name="ViSuaLBaSiC";
  System.out.println(shallow.get(0).getName()+"  "+deep.get(0).getName());

输出- ViSuaLBaSiC C

The copy constructor is used to initialize the new object with the previously created object of the same class. By default compiler wrote a shallow copy. Shallow copy works fine when dynamic memory allocation is not involved because when dynamic memory allocation is involved then both objects will points towards the same memory location in a heap, Therefore to remove this problem we wrote deep copy so both objects have their own copy of attributes in a memory. In order to read the details with complete examples and explanations you could see the article C++ constructors.

简单来说,浅拷贝类似于按引用调用,深拷贝类似于按值调用

在引用调用中,函数的形式参数和实际参数都指向相同的内存位置和值。

在按值调用中,函数的形式形参和实际形参都是指不同的内存位置,但具有相同的值。

为了便于理解,你可以参考这篇文章: https://www.cs.utexas.edu/~scottm/cs307/handouts/deepCopying.htm


浅拷贝:


深拷贝: