dla*_*lin 818

广度与深度; 根据您的对象作为根节点的引用树来思考.

浅:

复制前 浅层复制 浅浅的

变量A和B指的是不同的存储区域,当B被分配给A时,两个变量指的是相同的存储区域.以后对其中一个内容的修改会立即反映在其他内容中,因为它们共享内容.

深:

复制前 深度复制 做得很好

变量A和B指的是不同的存储区,当B被分配给存储区中的值时,A指向的值被复制到B指向的存储区中.后来对其中任何内容的修改仍然是A或B的唯一内容; 内容不共享.

  • 这是一个维基百科的文章,这个插图来自于你不具备上下文的理由http://en.wikipedia.org/wiki/Object_copy#Shallow_copy (30认同)
  • @jasonleonhard所以9年前我只是把网址放在图片上,因为不支持嵌入图片.因此URL引用了它的来源.社区后来将URL设置为嵌入式图像,而不对其进行某种引用.这篇4年前的评论也指出了你指出的内容.看看:https://stackoverflow.com/posts/184780/revisions为什么不自己编辑一个引用答案?下次有人抱怨我10岁的写作风格时,我可能会无法使用. (7认同)
  • “对于变量 A 和 B,当 B 分配给 A 时”在代码中是否意味着“A = B”?我有点困惑,因为图像反映了“B = A”。 (6认同)
  • 如果我们在数组A中进行任何更改,那么在浅层复制的情况下,由于A和B都指向相同的内存位置,因此会反映在数组A中吗? (4认同)
  • 在单行中,按引用复制vs按值复制.不确定答案是否正确! (2认同)
  • 图片直接取自维基百科而不引用 (2认同)

S.L*_*ott 726

浅拷贝尽可能少复制.集合的浅表副本是集合结构的副本,而不是元素.使用浅拷贝,两个集合现在共享各个元素.

深拷贝复制一切.集合的深层副本是两个集合,原始集合中的所有元素都是重复的.

  • 浅拷贝不会复制元素.S.Lott是对的. (24认同)
  • @RoyiNamir 在过去的 7 年中,您可能已经想通了这一点,但是对于其他对此感到疑惑的人:“_shallow copy 逐位复制值类型_”是正确的,但这有点令人困惑。如果您有一个“客户”对象,它“具有”一个“地址”对象,那么“一点一点”复制“客户”对象意味着复制到“地址”对象的**指针/引用**。Original 和 copy 都指向同一个 `Address` 对象,而深拷贝将创建一个新的 `Address` 对象并指向它。 (4认同)
  • 请记住,还有**混合副本**(不仅如[懒人副本](http://en.wikipedia.org/wiki/Object_copy#Lazy_copy)),它只复制了一部分([这里是一个实例](http://stackoverflow.com/a/12609692/274502))!;) (3认同)
  • 什么是集合结构? (2认同)

hel*_*dre 152

简而言之,这取决于什么指向什么.在浅拷贝中,对象B指向对象A在内存中的位置.在深层复制中,对象A的内存位置中的所有内容都会被复制到对象B的内存位置.

这篇wiki文章有一个很棒的图表.

http://en.wikipedia.org/wiki/Object_copy


Ale*_*ndr 89

尝试考虑下面的图像

在此输入图像描述

例如,Object.MemberwiseClone创建拷贝链接

并使用ICloneable接口,您可以获得此处所述的深层复制

  • 一张图片胜过千言万语. (22认同)
  • 哦,小伙子,来到这里找出意思.这是唯一有帮助的答案. (4认同)
  • 这是最简单的,但只显示了必要的内容。 (4认同)
  • 最好的插图 (3认同)
  • 这个答案解释了按引用复制与按值复制。浅拷贝与深拷贝是一个适用于集合的概念。请参阅此[答案](/sf/answers/1207272111/) 和此[答案](/sf/answers/3111222691/)。 (2认同)

Abh*_*edi 68

特别是对于iOS开发人员:

如果B浅拷贝A,那么它就像原始数据B = [A assign];和对象它像B = [A retain];

B和A指向相同的内存位置

如果B深拷贝A,那么它像B = [A copy];

B和A指向不同的存储位置

B存储器地址与A相同

B与A的内容相同

  • "B存储器地址与A的相同" - 为什么? (8认同)
  • 在深层复制中,"B存储器地址与A的不同" (2认同)

Mar*_*ork 59

浅拷贝:将成员值从一个对象复制到另一个对象.

深层复制:将成员值从一个对象复制到另一个对象.
                     任何指针对象都是重复的并且是深度复制的.

例:

class String
{
     int   size;
     char* data;
};

String  s1("Ace");   // s1.size = 3 s1.data=0x0000F000

String  s2 = shallowCopy(s1);
 // s2.size =3 s2.data = 0X0000F000
String  s3 = deepCopy(s1);
 // s3.size =3 s3.data = 0x0000F00F
 //                      (With Ace copied to this location.)
Run Code Online (Sandbox Code Playgroud)


Bil*_*l K 46

我在这里没有看到一个简短易懂的答案 - 所以我会试一试.

对于浅拷贝,源指向的任何对象也由目标指向(因此不会复制引用的对象).

使用深拷贝时,将复制源指向的任何对象,并且目标指向该副本(因此现在每个引用的对象将有2个).这会递归对象树.


Tou*_*one 41

只是为了便于理解,您可以遵循以下文章:https: //www.cs.utexas.edu/~scottm/cs307/handouts/deepCopying.htm


浅拷贝:

浅拷贝


深拷贝:

深拷贝


ha9*_*3ar 35

{想象一下两个对象:相同类型_t的A和B(关于C++),你正在考虑浅/深复制A到B}

浅层复制: 只需将A的引用复制到B中即可.将其视为A地址的副本.因此,A和B的地址将是相同的,即它们将指向相同的存储器位置,即数据内容.

深层复制: 只需复制A的所有成员,在B的不同位置分配内存,然后将复制的成员分配给B以实现深层复制.这样,如果A变为不存在,则B在存储器中仍然有效.正确使用的术语是克隆,你知道它们两者完全相同但却不同(即存储在内存空间中的两个不同的实体).您还可以提供克隆包装器,您可以通过包含/排除列表决定在深层复制期间选择哪些属性.创建API时,这是一种常见的做法.

您可以选择执行浅层复制ONLY_IF,了解所涉及的利害关系.当你有大量的指针需要在C++或C中处理时,做一个对象的浅表副本真的是个坏主意.

EXAMPLE_OF_DEEP COPY_例如,当您尝试进行图像处理和对象识别时,需要在处理区域之外屏蔽"不相关和重复运动".如果您正在使用图像指针,那么您可能具有保存这些蒙版图像的规范.现在......如果您执行图像的浅表复制,当指针引用从堆栈中被杀死时,您丢失了引用及其副本,即在某些时候存在访问冲突的运行时错误.在这种情况下,您需要的是克隆它的图像的深层副本.通过这种方式,您可以在将来需要时检索蒙版.

EXAMPLE_OF_SHALLOW_COPY与StackOverflow中的用户相比,我不是很了解,所以如果你能澄清的话,请随意删除这部分,并提供一个很好的例子.但是我真的认为如果你知道你的程序将会运行一段无限的时间来进行浅层复制并不是一个好主意,即通过函数调用在堆栈上连续进行"push-pop"操作.如果你向业余或新手演示某些东西(例如C/C++教程),那么它可能没问题.但是如果你正在运行一个应用程序,如监视和检测系统,或声纳跟踪系统,你不应该保持浅层复制你的对象,因为它迟早会杀死你的程序.


Joh*_*ing 32

char * Source = "Hello, world.";

char * ShallowCopy = Source;    

char * DeepCopy = new char(strlen(Source)+1);
strcpy(DeepCopy,Source);        
Run Code Online (Sandbox Code Playgroud)

'ShallowCopy'指向内存中与'Source'相同的位置.'DeepCopy'指向内存中的不同位置,但内容相同.


ati*_*mpi 21

什么是浅拷贝?

浅拷贝是对象的逐位副本.创建一个新对象,该对象具有原始对象中值的精确副本.如果对象的任何字段是对其他对象的引用,则仅复制引用地址,即仅复制存储器地址.浅拷贝

在此图中,MainObject1具有field1int ContainObject1类型和类型的字段ContainObject.当您执行浅拷贝时MainObject1,MainObject2创建时field2包含复制的值field1并仍指向ContainObject1自身.请注意,由于field1是原始类型,因此将其值复制到field2但是因为它ContainedObject1是一个对象,MainObject2仍然指向ContainObject1.所以所做的任何更改ContainObject1MainObject1将反映在MainObject2.

现在,如果这是浅拷贝,让我们看看什么是深拷贝?

什么是Deep Copy?

深拷贝会复制所有字段,并生成字段指向的动态分配内存的副本.将对象与其引用的对象一起复制时,会发生深层复制. 深拷贝

在此图中,MainObject1具有field1int ContainObject1类型和类型的字段ContainObject.当您执行深层复制时MainObject1,MainObject2创建时field2包含复制的值field1ContainObject2包含复制的值ContainObject1.请注意对ContainObject1in中所做的任何更改MainObject1都不会反映出来MainObject2.

好文章


Jef*_*dge 16

在面向对象的编程中,类型包括成员字段的集合.这些字段可以通过值或通过引用(即,指向值的指针)存储.

在浅表副本中,将创建该类型的新实例,并将值复制到新实例中.参考指针也像值一样被复制.因此,引用指向原始对象.对引用存储的成员所做的任何更改都会同时显示在原始对象和副本中,因为没有对引用的对象进行复制.

在深层复制中,按值存储的字段将像以前一样复制,但不会复制通过引用存储的对象的指针.相反,深度复制由引用的对象组成,并存储指向新对象的指针.对这些引用对象所做的任何更改都不会影响该对象的其他副本.


小智 12

'ShallowCopy'指向内存中与'Source'相同的位置.'DeepCopy'指向内存中的不同位置,但内容相同.


Aru*_*aaj 9

浅克隆:
定义:"对象的浅表副本复制'主'对象,但不复制内部对象." 当自定义对象(例如Employee)只有原始的String类型变量时,则使用Shallow Cloning.

Employee e = new Employee(2, "john cena");
Employee e2=e.clone();
Run Code Online (Sandbox Code Playgroud)

super.clone();在重写的clone()方法中返回,你的工作结束了.

深度克隆:
定义:"与浅拷贝不同,深拷贝是对象的完全独立副本."
表示Employee对象拥有另一个自定义对象时:

Employee e = new Employee(2, "john cena", new Address(12, "West Newbury", "Massachusetts");
Run Code Online (Sandbox Code Playgroud)

然后你必须编写代码来克隆'Address'对象以及重写的clone()方法.否则,Address对象将不会克隆,并且当您更改克隆的Employee对象中的Address值时会导致错误,这也反映了原始对象.


Dou*_*rch 8

var source = { firstName="Jane", lastname="Jones" };
var shallow = ShallowCopyOf(source);
var deep = DeepCopyOf(source);
source.lastName = "Smith";
WriteLine(source.lastName); // prints Smith
WriteLine(shallow.lastName); // prints Smith
WriteLine(deep.lastName); // prints Jones
Run Code Online (Sandbox Code Playgroud)


Sun*_*hoo 8

深拷贝

深拷贝会复制所有字段,并生成字段指向的动态分配内存的副本.将对象与其引用的对象一起复制时,会发生深层复制.

浅拷贝

浅拷贝是对象的逐位副本.创建一个新对象,该对象具有原始对象中值的精确副本.如果对象的任何字段是对其他对象的引用,则仅复制引用地址,即仅复制存储器地址.

深拷贝和浅拷贝的例子


小智 7

浅复制 - 原始和浅复制对象内的引用变量引用了公共对象.

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

克隆总是做浅拷贝.

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

主要课程如下 -

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

} 
Run Code Online (Sandbox Code Playgroud)

以上OutPut将 -

假真的是真的

虚假虚假

原始对象中的任何更改都将反映在浅层对象中,而不是深层对象中.

  list.get(0).name="ViSuaLBaSiC";
  System.out.println(shallow.get(0).getName()+"  "+deep.get(0).getName());
Run Code Online (Sandbox Code Playgroud)

OutPut- ViSuaLBaSiC C.


小智 7

浅拷贝构造一个新的复合对象并将其引用插入到原始对象中。

与浅拷贝不同,深拷贝构造新的复合对象,同时插入原始复合对象的原始对象的副本。

让我们举个例子。

import copy
x =[1,[2]]
y=copy.copy(x)
z= copy.deepcopy(x)
print(y is z)
Run Code Online (Sandbox Code Playgroud)

上面的代码打印 FALSE。

让我们看看如何。

原始复合对象x=[1,[2]](称为复合对象,因为它在对象内部有对象(Inception))

在此处输入图片说明

正如您在图像中看到的,列表中有一个列表。

然后我们使用y = copy.copy(x). python 在这里所做的是,它将创建一个新的复合对象,但其中的对象指向原始对象。

在此处输入图片说明

在图像中,它为外部列表创建了一个新副本。但内部列表保持与原始列表相同。

现在我们使用z = copy.deepcopy(x). python在这里所做的是,它将为外部列表和内部列表创建新对象。如下图所示(红色突出显示)。

在此处输入图片说明

最后代码打印False,因为 y 和 z 不是相同的对象。

哈。


小智 7

我想举例而不是正式定义.

var originalObject = { 
    a : 1, 
    b : 2, 
    c : 3,
};
Run Code Online (Sandbox Code Playgroud)

此代码显示浅拷贝:

var copyObject1 = originalObject;

console.log(copyObject1.a);         // it will print 1 
console.log(originalObject.a);       // it will also print 1 
copyObject1.a = 4; 
console.log(copyObject1.a);           //now it will print 4 
console.log(originalObject.a);       // now it will also print 4

var copyObject2 = Object.assign({}, originalObject);

console.log(copyObject2.a);        // it will print 1 
console.log(originalObject.a);      // it will also print 1 
copyObject2.a = 4; 
console.log(copyObject2.a);        // now it will print 4 
console.log(originalObject.a);      // now it will print 1
Run Code Online (Sandbox Code Playgroud)

此代码显示深层副本:

var copyObject2 = Object.assign({}, originalObject);

console.log(copyObject2.a);        // it will print 1 
console.log(originalObject.a);      // it will also print 1 
copyObject2.a = 4; 
console.log(copyObject2.a);        // now it will print 4 
console.log(originalObject.a);      // !! now it will print 1 !!
Run Code Online (Sandbox Code Playgroud)


not*_*ony 5

struct sample
{
    char * ptr;
}
void shallowcpy(sample & dest, sample & src)
{
    dest.ptr=src.ptr;
}
void deepcpy(sample & dest, sample & src)
{
    dest.ptr=malloc(strlen(src.ptr)+1);
    memcpy(dest.ptr,src.ptr);
}
Run Code Online (Sandbox Code Playgroud)


小智 5

在简单术语中,浅拷贝类似于按引用呼叫,深度拷贝类似于按值呼叫

在Call By Reference中,函数的形式参数和实际参数都指的是相同的内存位置和值.

在Call By Value中,函数的形式参数和实际参数都指的是不同的内存位置,但具有相同的值.


Pee*_*Net 5

想象一下,有两个名为arr1和arr2的数组.

arr1 = arr2;   //shallow copy
arr1 = arr2.clone(); //deep copy
Run Code Online (Sandbox Code Playgroud)