В чем разница между глубокой и мелкой копиями?
В чем разница между глубокой и мелкой копиями?
Ответы:
Мелкие копии дублируют как можно меньше. Мелкая копия коллекции - это копия структуры коллекции, а не ее элементы. С мелкой копией две коллекции теперь совместно используют отдельные элементы.
Глубокие копии дублируют все. Глубокая копия коллекции - это две коллекции со всеми дублированными элементами оригинальной коллекции.
Ширина против Глубины; мыслить в терминах дерева ссылок с вашим объектом в качестве корневого узла.
Мелкий:
Переменные A и B относятся к разным областям памяти, когда B присваивается A, две переменные относятся к одной и той же области памяти. Более поздние модификации содержимого любого из них немедленно отражаются в содержимом другого, поскольку они разделяют содержимое.
Deep:
Переменные A и B относятся к различным областям памяти, когда B присваивается A значения в области памяти, на которые указывает A, копируются в область памяти, на которую указывает B. Более поздние модификации содержимого либо остаются уникальными для A или B; содержание не передается.
Короче, это зависит от того, что указывает на что. В мелкой копии объект B указывает на местоположение объекта A в памяти. При глубоком копировании все вещи в ячейке памяти объекта A копируются в ячейку памяти объекта B.
Эта вики статья имеет отличную схему.
Попробуйте рассмотреть следующее изображение
Например, Object.MemberwiseClone создает ссылку для мелкого копирования
и используя интерфейс ICloneable, вы можете получить глубокое копирование, как описано здесь
Специально для разработчиков iOS:
Если B
это мелкая копия из A
, то для примитивных данных это , как B = [A assign];
и для объектов , это как B = [A retain]
;
B и A указывают на одну и ту же ячейку памяти
Если B
это глубокая копия из A
, то это какB = [A copy];
B и A указывают на разные области памяти
Адрес памяти B такой же, как и у A
Б имеет то же содержание, что и А
Мелкая копия: копирует значения элементов из одного объекта в другой.
Deep Copy: копирует значения элементов из одного объекта в другой.
Любые объекты указателя дублируются и копируются.
Пример:
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.)
Я не видел короткого, легкого для понимания ответа здесь - поэтому я попробую.
При неглубоком копировании любой объект, на который указывает источник, также указывается адресатом (так что ссылочные объекты не копируются).
При глубокой копии любой объект, на который указывает источник, копируется, а на копию указывает пункт назначения (так что теперь будет 2 из каждого ссылочного объекта). Это повторяется в дереве объектов.
Просто для простоты понимания вы можете следить за этой статьей: https://www.cs.utexas.edu/~scottm/cs307/handouts/deepCopying.htm
Мелкая копия:
Глубокая копия:
{Представьте себе два объекта: A и B одного и того же типа _t (по отношению к C ++), и вы думаете о мелком / глубоком копировании A в B}
Shallow Copy: просто делает копию ссылки на 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 ++), то это, вероятно, хорошо. Но если вы используете приложение, такое как система наблюдения и обнаружения, или Sonar Tracking System, вы не должны продолжать поверхностно копировать ваши объекты, потому что это рано или поздно убьет вашу программу.
char * Source = "Hello, world.";
char * ShallowCopy = Source;
char * DeepCopy = new char(strlen(Source)+1);
strcpy(DeepCopy,Source);
«ShallowCopy» указывает на то же место в памяти, что и «Source». «DeepCopy» указывает на другое место в памяти, но его содержимое одинаково.
Что такое мелкая копия?
Мелкая копия - побитовая копия объекта. Создается новый объект, который имеет точную копию значений в исходном объекте. Если какие-либо поля объекта являются ссылками на другие объекты, копируются только ссылочные адреса, т. Е. Копируется только адрес памяти.
На этом рисунке MainObject1
есть поля field1
типа int и ContainObject1
типа ContainObject
. Когда вы делаете мелкую копию MainObject1
, MainObject2
создается с field2
содержащим скопированное значение field1
и по-прежнему указывающим на ContainObject1
себя. Обратите внимание, что поскольку field1
это тип примитива, его значение копируется, field2
но, поскольку ContainedObject1
это объект, он MainObject2
все еще указывает на ContainObject1
. Таким образом, любые изменения, внесенные ContainObject1
в, MainObject1
будут отражены в MainObject2
.
Теперь, если это мелкая копия, давайте посмотрим, что такое глубокая копия?
Что такое Deep Copy?
Глубокая копия копирует все поля и создает копии динамически распределенной памяти, на которую указывают поля. Глубокое копирование происходит, когда объект копируется вместе с объектами, на которые он ссылается.
На этом рисунке MainObject1 имеет поля field1
типа int и ContainObject1
типа ContainObject
. Когда вы делаете глубокую копию MainObject1
, MainObject2
создается с field2
содержащим скопированное значение field1
и ContainObject2
содержащим скопированное значение ContainObject1
. Обратите внимание, что любые изменения, внесенные ContainObject1
в MainObject1
, не будут отражены в MainObject2
.
field3
который, когда в состоянии попытаться понять что-то настолько глубокое, как эта проблема, где же находится этот № 3 в этом примере ContainObject2
?
В объектно-ориентированном программировании тип включает в себя коллекцию полей-членов. Эти поля могут храниться либо по значению, либо по ссылке (т. Е. Указатель на значение).
В мелкой копии создается новый экземпляр типа, а значения копируются в новый экземпляр. Ссылочные указатели также копируются как значения. Поэтому ссылки указывают на исходные объекты. Любые изменения в элементах, которые хранятся по ссылке, отображаются как в оригинале, так и в копии, поскольку не было сделано ни одной копии ссылочного объекта.
При глубоком копировании поля, которые хранятся по значению, копируются, как и раньше, но указатели на объекты, сохраненные по ссылке, не копируются. Вместо этого делается глубокая копия ссылочного объекта, и указатель на новый объект сохраняется. Любые изменения, внесенные в эти объекты, на которые есть ссылки, не влияют на другие копии объекта.
«ShallowCopy» указывает на то же место в памяти, что и «Source». «DeepCopy» указывает на другое место в памяти, но его содержимое одинаково.
Неглубокое клонирование:
определение: «Неглубокая копия объекта копирует« основной »объект, но не копирует внутренние объекты». Когда пользовательский объект (например, Employee) имеет только примитивные переменные типа String, тогда вы используете Shallow Cloning.
Employee e = new Employee(2, "john cena");
Employee e2=e.clone();
Вы возвращаетесь super.clone();
в переопределенном методе clone (), и ваша работа закончена.
Глубокое клонирование :
определение: «В отличие от мелкой копии, глубокая копия является полностью независимой копией объекта».
Означает, что объект Employee содержит другой пользовательский объект:
Employee e = new Employee(2, "john cena", new Address(12, "West Newbury", "Massachusetts");
Затем вы должны написать код для клонирования объекта Address также в переопределенном методе clone (). В противном случае объект Address не будет клонирован, и это приведет к ошибке при изменении значения Address в клонированном объекте Employee, который также отражает исходный объект.
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
Deep Copy
Глубокая копия копирует все поля и создает копии динамически распределенной памяти, на которую указывают поля. Глубокое копирование происходит, когда объект копируется вместе с объектами, на которые он ссылается.
Мелкая копия
Мелкая копия - побитовая копия объекта. Создается новый объект, который имеет точную копию значений в исходном объекте. Если какие-либо поля объекта являются ссылками на другие объекты, копируются только ссылочные адреса, т. Е. Копируется только адрес памяти.
Shallow Copy - Ссылочная переменная внутри оригинальных и мелко скопированных объектов имеет ссылку на общий объект.
Deep Copy - Ссылочная переменная внутри оригинальных и глубоко скопированных объектов имеет ссылку на другой объект.
клон всегда делает мелкую копию.
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
}
OutPut выше будет
ложь правда правда
ложь ложь ложь
Любое изменение, сделанное в оригинальном объекте, отразится на мелком объекте, а не на глубоком объекте.
list.get(0).name="ViSuaLBaSiC";
System.out.println(shallow.get(0).getName()+" "+deep.get(0).getName());
OutPut- ViSuaLBaSiC C
Я хотел бы привести пример, а не формальное определение.
var originalObject = {
a : 1,
b : 2,
c : 3,
};
Этот код показывает мелкую копию :
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
Этот код показывает глубокую копию :
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
Проще говоря, мелкая копия похожа на вызов по ссылке, а глубокая копия похожа на вызов по значению
В вызове по ссылке как формальные, так и фактические параметры функции относятся к одной и той же ячейке памяти и значению.
В вызове по значению формальные и фактические параметры функции относятся к разным ячейкам памяти, но имеют одно и то же значение.
Мелкая копия создает новый составной объект и вставляет в него ссылки на исходный объект.
В отличие от мелкого копирования, deepcopy создает новый составной объект, а также вставляет копии исходных объектов исходного составного объекта.
Давайте возьмем пример.
import copy
x =[1,[2]]
y=copy.copy(x)
z= copy.deepcopy(x)
print(y is z)
Над кодом печатается ЛОЖЬ.
Давай посмотрим как.
Исходный составной объект x=[1,[2]]
(называется составным, потому что у него есть объект внутри объекта (Inception))
как вы можете видеть на картинке, внутри списка есть список.
Затем мы создаем поверхностную копию, используя y = copy.copy(x)
. Здесь Python создает новый составной объект, но объекты внутри него указывают на оригинальные объекты.
В изображении он создал новую копию для внешнего списка. но внутренний список остается таким же, как и исходный.
Теперь мы создаем его глубокую копию z = copy.deepcopy(x)
. Что Python делает здесь, так это то, что он создаст новый объект для внешнего списка, а также для внутреннего списка. как показано на рисунке ниже (выделено красным).
В конце кода печатается False
, так как y и z не являются одинаковыми объектами.
НТН.
При поверхностном копировании создается новый объект, а затем копируются нестатические поля текущего объекта в новый объект. Если поле является типом значения -> выполняется побитовая копия поля; для ссылочного типа -> ссылка копируется, а ссылочный объект - нет; поэтому исходный объект и его клон ссылаются на один и тот же объект.
Глубокая копия создает новый объект, а затем копирует нестатические поля текущего объекта в новый объект. Если поле является типом значения -> выполняется побитовая копия поля. Если поле является ссылочным типом -> выполняется новая копия упомянутого объекта. Клонируемые классы должны быть помечены как [Сериализуемые].
Взято из [блога]: http://sickprogrammersarea.blogspot.in/2014/03/technical-interview-questions-on-c_6.html
Глубокое копирование включает использование содержимого одного объекта для создания другого экземпляра того же класса. В глубокой копии два объекта могут содержать одну и ту же информацию, но целевой объект будет иметь свои собственные буферы и ресурсы. уничтожение любого объекта не повлияет на оставшийся объект. Перегруженный оператор присваивания создаст глубокую копию объектов.
Мелкое копирование включает в себя копирование содержимого одного объекта в другой экземпляр того же класса, создавая таким образом зеркальное отображение. Благодаря прямому копированию ссылок и указателей эти два объекта будут совместно использовать одно и то же внешнее содержимое другого объекта, что будет непредсказуемым.
Объяснение:
Используя конструктор копирования, мы просто копируем значения данных по элементам. Этот метод копирования называется мелким копированием. Если объект является простым классом, состоящим из встроенных типов и без указателей, это будет приемлемо. Эта функция будет использовать значения и объекты, и ее поведение не будет изменено с мелкой копией, копируются только адреса указателей, являющихся членами, а не значение, на которое указывает адрес. Значения данных объекта затем будут случайно изменены функцией. Когда функция выходит из области видимости, копия объекта со всеми его данными извлекается из стека.
Если объект имеет какие-либо указатели, необходимо выполнить глубокое копирование. При глубоком копировании объекта память выделяется для объекта в свободном хранилище, а указанные элементы копируются. Глубокая копия используется для объектов, которые возвращаются из функции.
Чтобы добавить больше к другим ответам,
Мелкая копия не создаст новую ссылку, но глубокая копия создаст новую ссылку.
Вот программа для объяснения глубокой и мелкой копии.
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 + "]";
}
}
Копирование статей:
Массив является классом, что означает, что это ссылочный тип, поэтому 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]);
}
мелкий клон означает, что копируется только память, представленная клонированным массивом.
Если массив содержит объекты типа значения, значения копируются ;
если массив содержит ссылочный тип, копируются только ссылки, поэтому в результате появляются два массива, члены которых ссылаются на одни и те же объекты .
Чтобы создать глубокую копию - там, где ссылочный тип дублируется, вы должны пройти через массив и клонировать каждый элемент вручную.
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]); }
Я пришел к пониманию из следующих строк.
При мелком копировании поля типа значения объекта (int, float, bool) копируются в целевой объект, а ссылочные типы объекта (строка, класс и т. Д.) Копируются как ссылки в целевой объект. В этой цели ссылочные типы будут указывать на место в памяти исходного объекта.
Глубокая копия копирует значение объекта и ссылочные типы в полную новую копию целевых объектов. Это означает, что как типам значений, так и ссылочным типам будут выделены новые ячейки памяти.
Помимо всех приведенных выше определений, еще один и наиболее часто используемый глубокий экземпляр находится в конструкторе копирования (или перегружающем операторе присваивания) класса.
Мелкая копия -> это когда вы не предоставляете конструктор копирования. Здесь копируется только объект, но копируются не все члены класса.
Глубокое копирование -> это когда вы решили реализовать конструктор копирования или присвоение перегрузки в своем классе и разрешить копирование всех членов класса.
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
}
Конструктор копирования используется для инициализации нового объекта ранее созданным объектом того же класса. По умолчанию компилятор написал поверхностную копию. Мелкое копирование работает хорошо, когда динамическое выделение памяти не задействовано, потому что, когда задействовано динамическое выделение памяти, оба объекта будут указывать на одну и ту же область памяти в куче. Поэтому, чтобы устранить эту проблему, мы написали глубокое копирование, чтобы оба объекта имели свою собственную копию атрибутов. в памяти. Для того, чтобы прочитать подробности с полными примерами и пояснениями, вы можете увидеть в статье конструкторы C ++ .