Qual é a diferença entre uma cópia profunda e uma cópia superficial?
Qual é a diferença entre uma cópia profunda e uma cópia superficial?
Respostas:
Cópias rasas duplicam o mínimo possível. Uma cópia superficial de uma coleção é uma cópia da estrutura da coleção, não dos elementos. Com uma cópia superficial, duas coleções agora compartilham os elementos individuais.
Cópias profundas duplicam tudo. Uma cópia profunda de uma coleção é composta por duas coleções com todos os elementos da coleção original duplicados.
Largura x Profundidade; pense em termos de uma árvore de referências com seu objeto como o nó raiz.
Raso:
As variáveis A e B se referem a diferentes áreas da memória, quando B é atribuído a A, as duas variáveis se referem à mesma área da memória. Modificações posteriores no conteúdo de um são refletidas instantaneamente no conteúdo de outros, à medida que compartilham o conteúdo.
Profundo:
As variáveis A e B se referem a diferentes áreas da memória, quando B é atribuído a A, os valores na área de memória que A aponta para são copiados na área de memória para a qual B aponta. Modificações posteriores no conteúdo de um permanecem exclusivas de A ou B; o conteúdo não é compartilhado.
Em resumo, depende de quais pontos apontam para o quê. Em uma cópia superficial, o objeto B aponta para a localização do objeto A na memória. Na cópia em profundidade, todas as coisas na localização da memória do objeto A são copiadas para a localização da memória do objeto B.
Este artigo wiki tem um ótimo diagrama.
Tente considerar a seguinte imagem
Por exemplo, Object.MemberwiseClone cria um link de cópia superficial
e usando ICloneable interface que você pode obter profunda cópia como descrito aqui
Especialmente para desenvolvedores de iOS:
Se B
for uma cópia superficial de A
, para dados primitivos é como B = [A assign];
e para objetos é como B = [A retain]
;
B e A apontam para o mesmo local de memória
Se B
é uma cópia profunda de A
, é comoB = [A copy];
B e A apontam para diferentes locais de memória
O endereço de memória B é igual ao de A
B tem o mesmo conteúdo que A
Cópia rasa: copia os valores dos membros de um objeto para outro.
Cópia profunda: copia os valores dos membros de um objeto para outro.
Quaisquer objetos ponteiros são duplicados e copiados em profundidade.
Exemplo:
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.)
Eu não vi uma resposta curta e fácil de entender aqui - então vou tentar.
Com uma cópia superficial, qualquer objeto apontado pela fonte também é apontado pelo destino (para que nenhum objeto referenciado seja copiado).
Com uma cópia detalhada, qualquer objeto apontado pela fonte é copiado e a cópia é apontada pelo destino (portanto, agora haverá 2 de cada objeto referenciado). Isso ocorre novamente na árvore de objetos.
Apenas para facilitar o entendimento, você pode seguir este artigo: https://www.cs.utexas.edu/~scottm/cs307/handouts/deepCopying.htm
Cópia rasa:
Cópia profunda:
{Imagine dois objetos: A e B do mesmo tipo _t (com relação ao C ++) e você está pensando em copiar superficialmente / profundamente A para B}
Cópia superficial: Simplesmente faça uma cópia da referência de A em B. Pense nela como uma cópia do endereço de A. Portanto, os endereços de A e B serão os mesmos, ou seja, estarão apontando para o mesmo local da memória, ou seja, o conteúdo dos dados.
Cópia detalhada: Simplesmente faz uma cópia de todos os membros de A, aloca memória em um local diferente para B e depois atribui os membros copiados a B para obter uma cópia profunda. Dessa forma, se A se tornar inexistente, B ainda será válido na memória. O termo correto a ser usado seria clonagem, onde você sabe que os dois são totalmente iguais, mas ainda assim diferentes (ou seja, armazenados como duas entidades diferentes no espaço da memória). Você também pode fornecer seu wrapper de clone, onde pode decidir, por meio da lista de inclusão / exclusão, quais propriedades selecionar durante a cópia em profundidade. Essa é uma prática bastante comum quando você cria APIs.
Você pode optar por fazer uma cópia rasa ONLY_IF se entender as apostas envolvidas. Quando você tem um número enorme de ponteiros para lidar em C ++ ou C, fazer uma cópia superficial de um objeto é REALMENTE uma má idéia.
EXAMPLE_OF_DEEP COPY_ Um exemplo é que, quando você está tentando fazer o processamento de imagens e o reconhecimento de objetos, precisa mascarar "Movimento irrelevante e repetitivo" fora de suas áreas de processamento. Se você estiver usando ponteiros de imagem, poderá ter a especificação para salvar essas imagens de máscara. AGORA ... se você fizer uma cópia superficial da imagem, quando as referências do ponteiro forem KILLED da pilha, você perderá a referência e sua cópia, ou seja, haverá um erro de tempo de execução da violação de acesso em algum momento. Nesse caso, o que você precisa é de uma cópia profunda da sua imagem CLONANDO-a. Dessa forma, você pode recuperar as máscaras, caso precise delas no futuro.
EXAMPLE_OF_SHALLOW_COPY Não tenho muito conhecimento em comparação com os usuários do StackOverflow, portanto, sinta-se à vontade para excluir esta parte e dar um bom exemplo, se puder esclarecer. Mas eu realmente acho que não é uma boa idéia fazer uma cópia superficial se você souber que seu programa será executado por um período infinito de tempo, isto é, operação contínua de "push-pop" sobre a pilha com chamadas de função. Se você está demonstrando algo para uma pessoa amadora ou iniciante (por exemplo, material tutorial em C / C ++), provavelmente está tudo bem. Mas se você estiver executando um aplicativo, como um sistema de vigilância e detecção, ou o Sonar Tracking System, não deverá copiar superficialmente seus objetos, pois isso matará seu programa mais cedo ou mais tarde.
char * Source = "Hello, world.";
char * ShallowCopy = Source;
char * DeepCopy = new char(strlen(Source)+1);
strcpy(DeepCopy,Source);
'ShallowCopy' aponta para o mesmo local na memória que 'Source'. 'DeepCopy' aponta para um local diferente na memória, mas o conteúdo é o mesmo.
O que é cópia rasa?
Cópia rasa é uma cópia em bits de um objeto. Um novo objeto é criado com uma cópia exata dos valores no objeto original. Se qualquer um dos campos do objeto for referência a outros objetos, apenas os endereços de referência serão copiados, ou seja, somente o endereço de memória será copiado.
Nesta figura, os MainObject1
campos temfield1
do tipo int e ContainObject1
do tipo ContainObject
. Quando você faz uma cópia superficial de MainObject1
, MainObject2
é criada field2
contendo o valor copiado field1
e ainda apontando para ContainObject1
si mesma. Observe que, como field1
é do tipo primitivo, seu valor é copiado para, field2
mas como ContainedObject1
é um objeto, MainObject2
ainda aponta para ContainObject1
. Portanto, quaisquer alterações feitas no ContainObject1
in MainObject1
serão refletidas MainObject2
.
Agora, se essa é uma cópia superficial, vamos ver o que é cópia profunda?
O que é cópia profunda?
Uma cópia profunda copia todos os campos e faz cópias da memória alocada dinamicamente, apontada pelos campos. Uma cópia profunda ocorre quando um objeto é copiado junto com os objetos aos quais se refere.
Nesta figura, o MainObject1 possui campos field1
do tipo int e ContainObject1
do tipo ContainObject
. Quando você faz uma cópia profunda de MainObject1
, MainObject2
é criado field2
contendo o valor copiado de field1
e ContainObject2
contendo o valor copiado de ContainObject1
. Observe que quaisquer alterações feitas em ContainObject1
in MainObject1
não serão refletidas em MainObject2
.
field3
que, em posição de tentar compreender algo tão profundo quanto esse problema, onde está ocorrendo o número 3 desse exemplo ContainObject2
?
Na programação orientada a objetos, um tipo inclui uma coleção de campos membros. Esses campos podem ser armazenados por valor ou por referência (ou seja, um ponteiro para um valor).
Em uma cópia superficial, uma nova instância do tipo é criada e os valores são copiados para a nova instância. Os ponteiros de referência também são copiados como os valores. Portanto, as referências estão apontando para os objetos originais. Quaisquer alterações nos membros que são armazenadas por referência aparecem no original e na cópia, já que nenhuma cópia foi feita do objeto referenciado.
Em uma cópia detalhada, os campos armazenados por valor são copiados como antes, mas os ponteiros para objetos armazenados por referência não são copiados. Em vez disso, é feita uma cópia profunda do objeto referenciado e um ponteiro para o novo objeto é armazenado. Quaisquer alterações feitas nos objetos referenciados não afetarão outras cópias do objeto.
'ShallowCopy' aponta para o mesmo local na memória que 'Source'. 'DeepCopy' aponta para um local diferente na memória, mas o conteúdo é o mesmo.
Clonagem
rasa : Definição: "Uma cópia superficial de um objeto copia o objeto 'principal', mas não copia os objetos internos." Quando um objeto personalizado (por exemplo, Employee) possui variáveis primitivas do tipo String, você usa a Clonagem rasa.
Employee e = new Employee(2, "john cena");
Employee e2=e.clone();
Você retorna super.clone();
no método clone () substituído e seu trabalho termina.
Clonagem Profunda :
Definição: "Ao contrário da cópia superficial, uma cópia profunda é uma cópia totalmente independente de um objeto".
Significa quando um objeto Employee mantém outro objeto customizado:
Employee e = new Employee(2, "john cena", new Address(12, "West Newbury", "Massachusetts");
Então você deve escrever o código para clonar o objeto 'Address' também no método clone () substituído. Caso contrário, o objeto Address não será clonado e causará um erro quando você alterar o valor de Address no objeto Employee clonado, o que reflete o original também.
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
Cópia profunda
Uma cópia profunda copia todos os campos e faz cópias da memória alocada dinamicamente, apontada pelos campos. Uma cópia profunda ocorre quando um objeto é copiado junto com os objetos aos quais se refere.
Cópia rasa
Cópia rasa é uma cópia em bits de um objeto. Um novo objeto é criado com uma cópia exata dos valores no objeto original. Se algum dos campos do objeto for referência a outros objetos, apenas os endereços de referência serão copiados, ou seja, somente o endereço de memória será copiado.
Cópia rasa - A variável de referência dentro dos objetos originais e copiados em pouca profundidade tem referência ao objeto comum .
Cópia Profunda - A variável de referência dentro de objetos originais e copiados em profundidade tem referência a objetos diferentes .
O clone sempre faz uma cópia superficial.
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();
}
}
classe principal está seguindo-
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
}
O resultado acima será
falso verdadeiro verdadeiro
falso falso falso
Qualquer alteração feita no objeto original irá refletir no objeto raso e não no objeto profundo.
list.get(0).name="ViSuaLBaSiC";
System.out.println(shallow.get(0).getName()+" "+deep.get(0).getName());
OutPut- ViSuaLBaSiC C
Eu gostaria de dar um exemplo, e não a definição formal.
var originalObject = {
a : 1,
b : 2,
c : 3,
};
Este código mostra uma cópia superficial :
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
Este código mostra uma cópia detalhada :
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 !!
1 1 4 4 4 4 4 4
Em termos simples, uma cópia rasa é semelhante a chamada por referência e uma cópia profunda é semelhante a chamada por valor
Em Chamada por referência, os parâmetros formais e reais de uma função se referem ao mesmo local de memória e ao valor.
Em Chamada por valor, os parâmetros formais e reais de uma função se referem a um local de memória diferente, mas com o mesmo valor.
Uma cópia superficial constrói um novo objeto composto e insere suas referências ao objeto original.
Diferentemente da cópia superficial, a cópia em profundidade constrói o novo objeto composto e também insere cópias dos objetos originais do objeto composto original.
Vamos dar um exemplo.
import copy
x =[1,[2]]
y=copy.copy(x)
z= copy.deepcopy(x)
print(y is z)
O código acima imprime FALSE.
Vamos ver como.
Objeto composto original x=[1,[2]]
(chamado como composto porque possui objeto dentro do objeto (Inception))
como você pode ver na imagem, há uma lista dentro da lista.
Em seguida, criamos uma cópia superficial usando y = copy.copy(x)
. O que o python faz aqui é: ele criará um novo objeto composto, mas os objetos dentro deles estão apontando para os objetos originais.
Na imagem, ele criou uma nova cópia para a lista externa. mas a lista interna permanece a mesma da lista original.
Agora criamos uma cópia em profundidade dele usando z = copy.deepcopy(x)
. o que o python faz aqui é, ele criará um novo objeto para a lista externa e a lista interna. como mostrado na imagem abaixo (destacado em vermelho).
No final, o código é impresso False
, pois y e z não são os mesmos objetos.
HTH.
A cópia rasa é criar um novo objeto e, em seguida, copiar os campos não estáticos do objeto atual para o novo objeto. Se um campo for um tipo de valor -> é executada uma cópia bit a bit do campo; para um tipo de referência -> a referência é copiada, mas o objeto referido não é; portanto, o objeto original e seu clone se referem ao mesmo objeto.
A cópia profunda está criando um novo objeto e, em seguida, copiando os campos não estáticos do objeto atual para o novo objeto. Se um campo é um tipo de valor -> é executada uma cópia bit a bit do campo. Se um campo for um tipo de referência -> uma nova cópia do objeto referido será executada. As classes a serem clonadas devem ser sinalizadas como [Serializable].
Retirado de [blog]: http://sickprogrammersarea.blogspot.in/2014/03/technical-interview-questions-on-c_6.html
A cópia profunda envolve o uso do conteúdo de um objeto para criar outra instância da mesma classe. Em uma cópia detalhada, os dois objetos podem conter as mesmas informações, mas o objeto de destino terá seus próprios buffers e recursos. a destruição de qualquer objeto não afetará o objeto restante. O operador de atribuição sobrecarregado criaria uma cópia profunda dos objetos.
Cópia rasa envolve copiar o conteúdo de um objeto em outra instância da mesma classe, criando assim uma imagem espelhada. Devido à cópia direta de referências e ponteiros, os dois objetos compartilharão o mesmo conteúdo externo do outro objeto, de forma imprevisível.
Explicação:
Usando um construtor de cópia, simplesmente copiamos os valores dos dados membro por membro. Esse método de cópia é chamado de cópia superficial. Se o objeto for uma classe simples, composta de tipos incorporados e sem ponteiros, isso seria aceitável. Essa função usaria os valores e os objetos e seu comportamento não seria alterado com uma cópia superficial, apenas os endereços dos ponteiros que são membros são copiados e não o valor para o qual o endereço está apontando. Os valores dos dados do objeto seriam alterados inadvertidamente pela função. Quando a função sai do escopo, a cópia do objeto com todos os seus dados é removida da pilha.
Se o objeto tiver ponteiros, é necessário executar uma cópia profunda. Com a cópia profunda de um objeto, a memória é alocada para o objeto no armazenamento gratuito e os elementos apontados são copiados. Uma cópia detalhada é usada para objetos retornados de uma função.
Para adicionar mais a outras respostas,
A cópia rasa não criará nova referência, mas a cópia profunda criará a nova referência.
Aqui está o programa para explicar a cópia profunda e superficial.
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 + "]";
}
}
Copiando ararys:
Matriz é uma classe, o que significa que é o tipo de referência; portanto, matriz1 = matriz2 resulta em duas variáveis que referenciam a mesma matriz.
Mas veja este exemplo:
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]);
}
clone superficial significa que apenas a memória representada pela matriz clonada é copiada.
Se a matriz contiver objetos do tipo valor, os valores serão copiados ;
se a matriz contiver um tipo de referência, apenas as referências serão copiadas. Portanto, existem duas matrizes cujos membros fazem referência aos mesmos objetos .
Para criar uma cópia detalhada - onde o tipo de referência é duplicado, você deve percorrer a matriz e clonar cada elemento manualmente.
private void button1_Click(object sender, EventArgs e) { int[] arr1 = new int[]{1,2,3,4,5}; int[] arr2 = new int[]{6,7,8,9,0}; MessageBox.Show(arr1[2] + " " + arr2[2]); arr2 = arr1; MessageBox.Show(arr1[2] + " " + arr2[2]); arr1[2] = 12; MessageBox.Show(arr1[2] + " " + arr2[2]); }
Eu vim a entender das seguintes linhas.
A cópia rasa copia um tipo de valor do objeto (int, float, bool) nos campos para o objeto de destino e os tipos de referência do objeto (string, classe etc.) são copiados como referências no objeto de destino. Nesse destino, os tipos de referência apontam para o local da memória do objeto de origem.
A cópia profunda copia o valor e os tipos de referência de um objeto em uma nova cópia completa dos objetos de destino. Isso significa que os tipos de valor e de referência receberão novos locais de memória.
Adicionando a todas as definições acima, uma cópia profunda mais comumente usada, está no construtor de cópias (ou oprator de atribuição de sobrecarga) da classe.
Cópia rasa -> é quando você não fornece um construtor de cópias. Aqui, apenas o objeto é copiado, mas nem todos os membros da classe são copiados.
Cópia profunda -> é quando você decide implementar o construtor de cópias ou a atribuição de sobrecarga em sua classe e permite copiar todos os membros da classe.
MyClass& MyClass(const MyClass& obj) // copy constructor for MyClass
{
// write your code, to copy all the members and return the new object
}
MyClass& operator=(const MyClass& obj) // overloading assignment operator,
{
// write your code, to copy all the members and return the new object
}
O construtor de cópia é usado para inicializar o novo objeto com o objeto criado anteriormente da mesma classe. Por padrão, o compilador escreveu uma cópia superficial. A cópia rasa funciona bem quando a alocação dinâmica de memória não está envolvida porque, quando a alocação dinâmica de memória está envolvida, os dois objetos apontam para o mesmo local da memória em um heap. Portanto, para remover esse problema, escrevemos uma cópia profunda para que os dois objetos tenham sua própria cópia dos atributos em uma memória. Para ler os detalhes com exemplos e explicações completos, você pode ver o artigo Construtores C ++ .