Чим відрізняється глибока копія від дрібної копії?
Чим відрізняється глибока копія від дрібної копії?
Відповіді:
Дрібні копії копіюються якомога менше. Неглибока копія колекції - це копія структури колекції, а не елементів. За допомогою дрібної копії дві колекції тепер діляться окремими елементами.
Глибокі копії все копіюють. Глибока копія колекції - це дві колекції з усіма елементами оригінальної колекції.
Ширина проти глибини; подумайте з точки зору дерева посилань на ваш об'єкт як кореневий вузол.
Дрібні:
Змінні A і B відносяться до різних областей пам'яті, коли B призначено A, дві змінні відносяться до тієї ж області пам'яті. Пізніші зміни змісту будь-якого миттєво відображаються на вмісті інших, оскільки вони поділяють вміст.
Глибокий:
Змінні 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 така сама, як і А
B має той самий вміст, що й А
Неглибока копія: копіює значення учасника з одного об'єкта в інший.
Глибока копія: копіює значення учасників з одного об'єкта в інший.
Будь-які об’єкти вказівника дублюються та глибоко копіюються.
Приклад:
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}
Неглибока копія: просто робить копію посилання на А на Б. Подумайте про це як про копію Адреса А. Отже, адреси 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, ви не повинні тримати копіювати об’єкти навколо, оскільки це рано чи пізно знищить вашу програму.
char * Source = "Hello, world.";
char * ShallowCopy = Source;
char * DeepCopy = new char(strlen(Source)+1);
strcpy(DeepCopy,Source);
"ShallowCopy" вказує на те саме місце в пам'яті, що і "Джерело". 'DeepCopy' вказує на інше місце в пам'яті, але вміст той самий.
Що таке "Неглибока копія"?
Неглибока копія - це трохи розумна копія об'єкта. Створюється новий об’єкт, який має точну копію значень у вихідному об'єкті. Якщо будь-яке з полів об'єкта є посиланнями на інші об'єкти, копіюються лише довідкові адреси, тобто копіюється лише адреса пам'яті.
На цьому малюнку MainObject1
є поля field1
типу int та ContainObject1
type ContainObject
. Коли ви робите дрібну копію MainObject1
, MainObject2
створюється з field2
вмістом скопійованого значення field1
та все ще вказує на ContainObject1
себе. Зауважте, що оскільки field1
має примітивний тип, його значення копіюється, field2
але оскільки ContainedObject1
є об'єктом, MainObject2
все ще вказує на ContainObject1
. Таким чином , будь-які зміни , внесені ContainObject1
в MainObject1
будуть відображені в MainObject2
.
Тепер, якщо це неглибока копія, давайте подивимось, що таке глибока копія?
Що таке глибока копія?
Глибока копія копіює всі поля та робить копії динамічно розподіленої пам'яті, на яку вказують поля. Глибока копія виникає, коли об'єкт копіюється разом з об'єктами, на які він посилається.
На цьому малюнку MainObject1 мають поля field1
типу int та ContainObject1
type ContainObject
. Коли ви робите глибоку копію MainObject1
, MainObject2
створюється, field2
що містить скопійоване значення field1
та ContainObject2
містить скопійоване значення ContainObject1
. Зауважте, що будь-які зміни, внесені ContainObject1
в MainObject1
, не відображатимуться в MainObject2
.
field3
що коли ти можеш спробувати зрозуміти щось настільки глибоке, як це питання, де це №3 у цьому прикладі має місце ContainObject2
?
В об'єктно-орієнтованому програмуванні тип включає колекцію полів-членів. Ці поля можуть зберігатися як за значенням, так і за посиланням (тобто, вказівником на значення).
У неглибокій копії створюється новий екземпляр типу і значення копіюються в новий екземпляр. Опорні покажчики також копіюються так само, як і значення. Тому посилання вказують на оригінальні об’єкти. Будь-які зміни членів, які зберігаються за посиланням, з'являються як в оригіналі, так і в копії, оскільки жодна копія згаданого об'єкта не була зроблена.
У глибокій копії поля, які зберігаються за значенням, копіюються, як і раніше, але вказівники на об'єкти, що зберігаються за посиланням, не копіюються. Натомість, із посилається на об'єкт робиться глибока копія і зберігається вказівник на новий об’єкт. Будь-які зміни, внесені до цих посилань, не впливатимуть на інші копії об'єкта.
"ShallowCopy" вказує на те саме місце в пам'яті, що і "Джерело". 'DeepCopy' вказує на інше місце в пам'яті, але вміст той самий.
Дрібне клонування:
Визначення: "Неглибока копія об'єкта копіює" головний "об'єкт, але не копіює внутрішні об'єкти." Якщо користувацький об’єкт (наприклад, співробітник) має просто примітивні, змінні типу String, то ви використовуєте «Дрібне клонування».
Employee e = new Employee(2, "john cena");
Employee e2=e.clone();
Ви повертаєтесь super.clone();
за методом перекритого clone () і ваше завдання закінчено.
Глибоке клонування :
Визначення: "На відміну від дрібної копії, глибока копія є повністю незалежною копією об'єкта."
Означає, коли об’єкт Співробітник містить інший спеціальний об’єкт:
Employee e = new Employee(2, "john cena", new Address(12, "West Newbury", "Massachusetts");
Тоді вам доведеться написати код, щоб клонувати об’єкт "Адреса", а також методом перекритого clone (). В іншому випадку об'єкт 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
Глибока копія
Глибока копія копіює всі поля та робить копії динамічно розподіленої пам'яті, на яку вказують поля. Глибока копія виникає, коли об'єкт копіюється разом з об'єктами, на які він посилається.
Неглибока копія
Неглибока копія - це трохи розумна копія об'єкта. Створюється новий об’єкт, який має точну копію значень у вихідному об'єкті. Якщо будь-яке з полів об'єкта посилається на інші об'єкти, просто копіюються посилання адреси, тобто копіюється лише адреса пам'яті.
Дрібна копія - Довідкова змінна всередині оригінальних та неглибоко скопійованих об'єктів має посилання на загальний об'єкт.
Глибока копія - довідкова змінна всередині оригінальних та глибоко скопійованих об'єктів має посилання на різний об'єкт.
клон завжди робить дрібну копію.
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());
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
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);
}
Простіше кажучи, «Неглибока копія» схожа на «Дзвінок за посиланням», а «Глибока копія» схожа на «Дзвінок за значенням»
У Call By Reference як формальні, так і фактичні параметри функції відносяться до одного і того ж місця пам'яті та значення.
У "Call By Value" як формальні, так і фактичні параметри функції відносяться до іншого місця пам'яті, але мають однакове значення.
Неглибока копія конструює новий складний об’єкт і вставляє в нього посилання на оригінальний об'єкт.
На відміну від дрібної копії, deepcopy конструює новий складний об'єкт, а також вставляє копії оригінальних об'єктів оригінального складеного об'єкта.
Давайте візьмемо приклад.
import copy
x =[1,[2]]
y=copy.copy(x)
z= copy.deepcopy(x)
print(y is z)
Наведений вище код друкує FALSE.
Побачимо, як.
Оригінальний складений об'єкт x=[1,[2]]
(називається складовим, тому що він має об'єкт всередині об'єкта (Inception))
як ви бачите на зображенні, всередині є список.
Потім ми створюємо її неглибоку копію, використовуючи y = copy.copy(x)
. Що тут робить python, він створить новий складний об'єкт, але об'єкти всередині них вказують на оригінальні об'єкти.
Зображення створило нову копію для зовнішнього списку. але внутрішній список залишається таким же, як і оригінальний.
Тепер ми створюємо глибоку копію, використовуючи z = copy.deepcopy(x)
. що python робить тут, це створить новий об'єкт для зовнішнього списку, а також внутрішнього списку. як показано на зображенні нижче (виділено червоним кольором).
У кінці друкується код False
, оскільки y і z не є однаковими об'єктами.
HTH.
Дрібне копіювання - це створення нового об'єкта, а потім копіювання нестатичних полів поточного об'єкта до нового об’єкта. Якщо поле є типом значення -> виконується побітова копія поля; для типу посилання -> посилання копіюється, але згаданий об'єкт не є; тому оригінальний об'єкт і його клон відносяться до одного і того ж об'єкта.
Глибока копія - це створення нового об'єкта, а потім копіювання нестатичних полів поточного об'єкта до нового об’єкта. Якщо поле є типом значення -> виконується побітна копія поля. Якщо поле є типовим типом -> виконується нова копія згаданого об'єкта. Класи, які потрібно клонувати, повинні бути позначені як [Serializable].
Взято з [блогу]: http://sickprogrammersarea.blogspot.in/2014/03/technical-interview-questions-on-c_6.html
Глибока копія передбачає використання вмісту одного об’єкта для створення іншого екземпляра того ж класу. У глибокій копії два об'єкти можуть містити ht однакову інформацію, але цільовий об’єкт матиме власні буфери та ресурси. знищення будь-якого об'єкта не вплине на решту об'єкта. Перевантажений оператор призначення створив би глибоку копію об'єктів.
Дрібна копія передбачає копіювання вмісту одного об’єкта в інший екземпляр того ж класу, створюючи дзеркальне зображення. Завдяки прямому копіюванню посилань та покажчиків, два об'єкти матимуть однаковий вміст іншого об'єкта, який міститиме зовнішній вигляд, непередбачуваним.
Пояснення:
Використовуючи конструктор копій, ми просто копіюємо значення даних членами члена. Цей спосіб копіювання називається дрібною копією. Якщо об'єкт - простий клас, що складається з вбудованих типів і не має вказівників, це було б прийнятно. Ця функція використовує значення, і об'єкти, і її поведінка не буде змінена дрібною копією, копіюються лише адреси покажчиків, які є членами, а не значення, на яке вказує адреса. Значення даних об'єкта потім будуть ненавмисно змінені функцією. Коли функція виходить за межі, копія об'єкта з усіма його даними вискакує з стека.
Якщо на об'єкті є якісь покажчики, потрібно виконати глибоку копію. За допомогою глибокої копії об'єкта для об'єкта виділяється пам'ять у вільному зберіганні, а елементи, на які вказується, копіюються. Глибока копія використовується для об'єктів, які повертаються з функції.
Щоб додати більше інших відповідей,
Дрібна копія не створить нову довідку, але глибока копія створить нову посилання.
Ось програма для пояснення глибокої та дрібної копії.
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 ++ конструктори .