Apa perbedaan antara salinan dalam dan salinan dangkal?
Apa perbedaan antara salinan dalam dan salinan dangkal?
Jawaban:
Salinan dangkal duplikat sesedikit mungkin. Salinan dangkal koleksi adalah salinan struktur koleksi, bukan elemen. Dengan salinan dangkal, dua koleksi sekarang berbagi elemen individu.
Salinan yang dalam menggandakan semuanya. Salinan dalam koleksi adalah dua koleksi dengan semua elemen dalam koleksi asli digandakan.
Luasnya vs Kedalaman; berpikir dalam hal pohon referensi dengan objek Anda sebagai simpul root.
Dangkal:
Variabel A dan B merujuk ke area memori yang berbeda, ketika B ditugaskan ke A, kedua variabel merujuk ke area memori yang sama. Kemudian modifikasi pada konten keduanya langsung tercermin dalam konten lainnya, karena mereka berbagi konten.
Dalam:
Variabel A dan B merujuk ke area memori yang berbeda, ketika B ditugaskan ke A nilai-nilai di area memori yang A menunjuk ke disalin ke area memori yang B menunjuk. Kemudian modifikasi pada konten keduanya tetap unik untuk A atau B; isinya tidak dibagikan.
Singkatnya, itu tergantung pada poin apa. Dalam salinan dangkal, objek B menunjuk ke lokasi objek A di memori. Dalam penyalinan dalam, semua hal di lokasi memori objek A disalin ke lokasi memori objek B.
Artikel wiki ini memiliki diagram yang bagus.
Coba pertimbangkan gambar berikut
Misalnya Object.MemberwiseClone membuat salinan dangkal tautan
dan menggunakan antarmuka ICloneable Anda bisa mendapatkan salinan dalam seperti yang dijelaskan di sini
Khusus Untuk Pengembang iOS:
Jika B
adalah salinan dangkal dari A
, maka untuk data primitif itu seperti B = [A assign];
dan untuk benda-benda itu seperti B = [A retain]
;
B dan A menunjuk ke lokasi memori yang sama
Jika B
adalah copy dalam dari A
, maka itu sepertiB = [A copy];
B dan A menunjuk ke lokasi memori yang berbeda
Alamat memori B sama dengan A
B memiliki konten yang sama dengan A
Salinan dangkal: Menyalin nilai anggota dari satu objek ke objek lainnya.
Salinan Jauh: Menyalin nilai anggota dari satu objek ke objek lainnya.
Setiap objek pointer digandakan dan Disalin Dalam.
Contoh:
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.)
Saya belum melihat jawaban yang singkat dan mudah dipahami di sini - jadi saya akan mencobanya.
Dengan salinan dangkal, objek apa pun yang ditunjukkan oleh sumber juga ditunjukkan oleh tujuan (sehingga tidak ada objek yang direferensikan disalin).
Dengan salinan yang dalam, objek apa pun yang ditunjuk oleh sumber akan disalin dan salinannya diarahkan ke tujuan (jadi sekarang akan ada 2 dari setiap objek yang direferensikan). Ini berulang ke pohon objek.
Hanya demi pemahaman yang mudah, Anda dapat mengikuti artikel ini: https://www.cs.utexas.edu/~scottm/cs307/handouts/deepCopying.htm
Salinan dangkal:
Salinan Dalam:
{Bayangkan dua objek: A dan B dengan jenis yang sama _t (sehubungan dengan C ++) dan Anda berpikir tentang penyalinan dangkal / dalam A ke B}
Salinan Dangkal: Cukup buat salinan referensi ke A ke B. Pikirkan sebagai salinan Alamat A. Jadi, alamat A dan B akan sama yaitu mereka akan menunjuk ke lokasi memori yang sama yaitu isi data.
Salinan dalam: Cukup buat salinan dari semua anggota A, alokasikan memori di lokasi yang berbeda untuk B dan kemudian tetapkan anggota yang disalin ke B untuk mendapatkan salinan yang dalam. Dengan cara ini, jika A menjadi tidak ada, B masih valid dalam memori. Istilah yang benar untuk digunakan adalah kloning, di mana Anda tahu bahwa keduanya sama, tetapi berbeda (yaitu disimpan sebagai dua entitas yang berbeda dalam ruang memori). Anda juga dapat memberikan pembungkus klon di mana Anda dapat memutuskan melalui daftar inklusi / pengecualian properti mana yang akan dipilih selama penyalinan dalam. Ini adalah praktik yang cukup umum ketika Anda membuat API.
Anda dapat memilih untuk melakukan Salinan Dangkal ONLY_IF Anda memahami taruhannya. Ketika Anda memiliki sejumlah besar pointer untuk berurusan dengan C ++ atau C, melakukan salinan objek yang dangkal benar - benar ide yang buruk.
EXAMPLE_OF_DEEP COPY_ Contohnya adalah, ketika Anda mencoba melakukan pemrosesan gambar dan pengenalan objek, Anda perlu menutupi "Gerakan Tidak Relevan dan Berulang-ulang" dari area pemrosesan Anda. Jika Anda menggunakan penunjuk gambar, maka Anda mungkin memiliki spesifikasi untuk menyimpan gambar topeng itu. SEKARANG ... jika Anda melakukan salinan gambar yang dangkal, ketika referensi pointer DIBUNUH dari tumpukan, Anda kehilangan referensi dan salinannya yaitu akan ada kesalahan runtime pelanggaran akses di beberapa titik. Dalam hal ini, yang Anda butuhkan adalah salinan gambar Anda yang dalam dengan mengkloningnya. Dengan cara ini Anda dapat mengambil topeng jika Anda membutuhkannya di masa depan.
EXAMPLE_OF_SHALLOW_COPY Saya tidak terlalu berpengetahuan dibandingkan dengan pengguna di StackOverflow jadi jangan ragu untuk menghapus bagian ini dan memberikan contoh yang baik jika Anda bisa mengklarifikasi. Tapi saya benar-benar berpikir itu bukan ide yang baik untuk melakukan copy dangkal jika Anda tahu bahwa program Anda akan berjalan untuk waktu yang tak terbatas yaitu operasi "push-pop" terus menerus selama stack dengan panggilan fungsi. Jika Anda mendemonstrasikan sesuatu kepada orang amatir atau pemula (mis. C / C ++ tutorial stuff) maka mungkin tidak apa-apa. Tetapi jika Anda menjalankan aplikasi seperti sistem pengawasan dan deteksi, atau Sistem Pelacakan Sonar, Anda tidak seharusnya terus menyalin objek Anda dengan dangkal karena itu akan membunuh program Anda cepat atau lambat.
char * Source = "Hello, world.";
char * ShallowCopy = Source;
char * DeepCopy = new char(strlen(Source)+1);
strcpy(DeepCopy,Source);
'ShallowCopy' menunjuk ke lokasi yang sama dalam memori seperti 'Sumber'. 'DeepCopy' menunjuk ke lokasi yang berbeda dalam memori, tetapi isinya sama.
Apa itu Salinan Dangkal?
Salinan dangkal adalah salinan objek yang sedikit bijaksana. Objek baru dibuat yang memiliki salinan tepat dari nilai-nilai di objek asli. Jika salah satu bidang objek referensi ke objek lain, hanya alamat referensi yang disalin yaitu, hanya alamat memori yang disalin.
Dalam gambar ini, MainObject1
memiliki bidang field1
tipe int, dan ContainObject1
tipe ContainObject
. Ketika Anda melakukan salinan dangkal MainObject1
, MainObject2
dibuat dengan field2
berisi nilai yang disalin field1
dan masih menunjuk ke ContainObject1
dirinya sendiri. Perhatikan bahwa karena field1
ini adalah tipe primitif, nilainya disalin field2
tetapi karena ContainedObject1
merupakan objek, MainObject2
masih menunjuk ke ContainObject1
. Jadi setiap perubahan yang dilakukan ContainObject1
pada MainObject1
akan tercermin dalam MainObject2
.
Sekarang jika ini adalah salinan dangkal, mari kita lihat apa yang ada di dalamnya?
Apa itu Deep Copy?
Salinan yang dalam menyalin semua bidang, dan membuat salinan dari memori yang dialokasikan secara dinamis ditunjuk oleh bidang tersebut. Salinan dalam terjadi ketika suatu objek disalin bersama dengan objek yang dirujuk.
Dalam gambar ini, MainObject1 memiliki bidang field1
tipe int, dan ContainObject1
tipe ContainObject
. Ketika Anda melakukan salinan dalam MainObject1
, MainObject2
dibuat dengan field2
berisi nilai yang disalin field1
dan ContainObject2
mengandung nilai yang disalin ContainObject1
. Perhatikan bahwa perubahan apa pun yang dilakukan ContainObject1
pada MainObject1
tidak akan mencerminkan MainObject2
.
field3
yang ketika dalam posisi mencoba dan memahami sesuatu sedalam masalah itu, di mana # 3 dalam contoh itu terjadi ContainObject2
?
Dalam pemrograman berorientasi objek, tipe menyertakan kumpulan bidang anggota. Bidang-bidang ini dapat disimpan dengan nilai atau referensi (yaitu, penunjuk ke nilai).
Dalam salinan dangkal, instance baru dari tipe dibuat dan nilai-nilai disalin ke instance baru. Pointer referensi juga disalin seperti nilainya. Oleh karena itu, referensi menunjuk ke objek aslinya. Setiap perubahan pada anggota yang disimpan dengan referensi muncul di dokumen asli dan salinan, karena tidak ada salinan yang dibuat dari objek yang direferensikan.
Dalam salinan yang dalam, bidang yang disimpan oleh nilai disalin seperti sebelumnya, tetapi pointer ke objek yang disimpan oleh referensi tidak disalin. Sebagai gantinya, salinan yang dalam dibuat dari objek yang direferensikan, dan sebuah pointer ke objek baru disimpan. Setiap perubahan yang dilakukan pada objek yang direferensikan tidak akan mempengaruhi salinan objek lainnya.
'ShallowCopy' menunjuk ke lokasi yang sama dalam memori seperti 'Sumber'. 'DeepCopy' menunjuk ke lokasi yang berbeda dalam memori, tetapi isinya sama.
Kloning Dangkal:
Definisi: "Salinan dangkal suatu objek menyalin objek 'utama', tetapi tidak menyalin objek dalam." Ketika objek kustom (mis. Karyawan) baru saja primitif, variabel tipe String maka Anda menggunakan Kloning Dangkal.
Employee e = new Employee(2, "john cena");
Employee e2=e.clone();
Anda kembali super.clone();
dengan metode clone () yang ditimpa dan pekerjaan Anda selesai.
Kloning Dalam :
Definisi: "Berbeda dengan salinan yang dangkal, salinan yang dalam adalah salinan yang sepenuhnya independen dari suatu objek."
Berarti ketika objek Karyawan memegang objek kustom lain:
Employee e = new Employee(2, "john cena", new Address(12, "West Newbury", "Massachusetts");
Maka Anda harus menulis kode untuk mengkloning objek 'Alamat' juga dalam metode clone () yang diganti. Jika tidak, objek Alamat tidak akan dikloning dan menyebabkan bug ketika Anda mengubah nilai Alamat di objek Karyawan yang dikloning, yang mencerminkan yang asli juga.
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
Salinan Yang Dalam
Salinan yang dalam menyalin semua bidang, dan membuat salinan dari memori yang dialokasikan secara dinamis ditunjuk oleh bidang tersebut. Salinan dalam terjadi ketika suatu objek disalin bersama dengan objek yang dirujuk.
Salinan dangkal
Salinan dangkal adalah salinan objek yang sedikit bijaksana. Objek baru dibuat yang memiliki salinan tepat dari nilai-nilai di objek asli. Jika salah satu bidang objek referensi ke objek lain, hanya alamat referensi yang disalin yaitu, hanya alamat memori yang disalin.
Salinan Dangkal - Variabel referensi di dalam objek asli dan disalin dangkal memiliki referensi ke objek umum .
Salinan Jauh - Variabel referensi di dalam objek asli dan yang disalin memiliki referensi ke objek yang berbeda .
klon selalu melakukan salinan dangkal.
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();
}
}
kelas utama mengikuti-
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 di atas akan menjadi-
salah benar benar
false false false
Setiap perubahan yang dilakukan pada objek asli akan mencerminkan objek dangkal tidak dalam objek yang mendalam.
list.get(0).name="ViSuaLBaSiC";
System.out.println(shallow.get(0).getName()+" "+deep.get(0).getName());
OutPut- ViSuaLBaSiC C
Saya ingin memberi contoh daripada definisi formal.
var originalObject = {
a : 1,
b : 2,
c : 3,
};
Kode ini menunjukkan salinan dangkal :
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
Kode ini menunjukkan salinan dalam :
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
Dalam Ketentuan Sederhana, Salinan Dangkal mirip dengan Call By Reference dan Deep Copy mirip dengan Call By Value
Dalam Call By Reference, parameter formal dan aktual dari suatu fungsi merujuk ke lokasi memori yang sama dan nilainya.
Dalam Nilai Panggilan Menurut, parameter formal dan aktual dari suatu fungsi merujuk ke lokasi memori yang berbeda tetapi memiliki nilai yang sama.
Salinan dangkal membangun objek majemuk baru dan memasukkan referensi ke dalamnya ke objek asli.
Tidak seperti salinan dangkal, deepcopy membangun objek senyawa baru dan juga menyisipkan salinan objek asli objek senyawa asli.
Mari kita ambil contoh.
import copy
x =[1,[2]]
y=copy.copy(x)
z= copy.deepcopy(x)
print(y is z)
Kode di atas mencetak SALAH.
Coba lihat caranya.
Objek majemuk asli x=[1,[2]]
(disebut senyawa karena memiliki objek di dalam objek (Inception))
seperti yang Anda lihat pada gambar, ada daftar di dalam daftar.
Lalu kami membuat salinan dangkal menggunakan y = copy.copy(x)
. Apa yang python lakukan di sini adalah, ia akan membuat objek majemuk baru tetapi objek di dalamnya menunjuk ke objek orignal.
Dalam gambar itu telah membuat salinan baru untuk daftar luar. tetapi daftar bagian dalam tetap sama dengan yang asli.
Sekarang kami membuat deepcopy menggunakan itu z = copy.deepcopy(x)
. apa yang python lakukan di sini adalah, itu akan membuat objek baru untuk daftar luar maupun daftar dalam. seperti yang ditunjukkan pada gambar di bawah (disorot merah).
Pada kode akhir dicetak False
, karena y dan z bukan objek yang sama.
HTH.
Salinan dangkal adalah membuat objek baru dan kemudian menyalin bidang non-statis objek saat ini ke objek baru. Jika bidang adalah tipe nilai -> salinan bidang sedikit demi sedikit dilakukan; untuk tipe referensi -> referensi disalin tetapi objek yang dirujuk tidak; Oleh karena itu objek asli dan klonnya merujuk pada objek yang sama.
Dalam copy adalah menciptakan objek baru dan kemudian menyalin bidang nonstatic dari objek saat ini ke objek baru. Jika bidang adalah tipe nilai -> salinan bidang sedikit demi sedikit dilakukan. Jika bidang adalah tipe referensi -> salinan baru dari objek yang dirujuk dilakukan. Kelas yang akan dikloning harus ditandai sebagai [Serializable].
Diambil dari [blog]: http://sickprogrammersarea.blogspot.in/2014/03/technical-interview-questions-on-c_6.html
Salinan mendalam melibatkan penggunaan konten dari satu objek untuk membuat instance lain dari kelas yang sama. Dalam salinan yang dalam, kedua objek mungkin berisi informasi yang sama tetapi objek target akan memiliki buffer dan sumber dayanya sendiri. penghancuran salah satu objek tidak akan mempengaruhi objek yang tersisa. Operator tugas yang kelebihan beban akan membuat salinan objek yang dalam.
Salinan dangkal melibatkan menyalin konten dari satu objek ke instance lain dari kelas yang sama sehingga menciptakan gambar cermin. Karena penyalinan langsung referensi dan petunjuk, kedua objek akan berbagi konten yang sama secara eksternal dari objek lain menjadi tidak dapat diprediksi.
Penjelasan:
Menggunakan copy constructor kami cukup menyalin nilai data anggota dengan anggota. Metode penyalinan ini disebut salinan dangkal. Jika objek adalah kelas sederhana, terdiri dari tipe bawaan dan tidak ada pointer ini akan diterima. Fungsi ini akan menggunakan nilai-nilai dan objek-objek dan perilakunya tidak akan diubah dengan salinan dangkal, hanya alamat pointer yang anggota disalin dan bukan nilai alamat yang menunjuk. Nilai data objek kemudian akan secara tidak sengaja diubah oleh fungsi. Ketika fungsi keluar dari ruang lingkup, salinan objek dengan semua datanya muncul dari tumpukan.
Jika objek memiliki pointer, salinan yang dalam perlu dieksekusi. Dengan salinan mendalam dari suatu objek, memori dialokasikan untuk objek di toko bebas dan elemen yang ditunjuk untuk disalin. Salinan dalam digunakan untuk objek yang dikembalikan dari suatu fungsi.
Untuk menambahkan lebih banyak ke jawaban lain,
Salinan dangkal tidak akan membuat referensi baru tetapi salinan yang dalam akan membuat referensi baru.
Berikut adalah program untuk menjelaskan salinan yang dalam dan dangkal.
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 + "]";
}
}
Salinan salinan:
Array adalah kelas, yang artinya adalah tipe referensi sehingga array1 = array2 menghasilkan dua variabel yang mereferensikan array yang sama.
Tapi lihat contoh ini:
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 dangkal berarti bahwa hanya memori yang diwakili oleh array yang dikloning disalin.
Jika array berisi objek tipe nilai, nilai disalin ;
jika array berisi tipe referensi, hanya referensi yang disalin - sehingga ada dua array yang anggotanya mereferensikan objek yang sama .
Untuk membuat salinan yang dalam — di mana tipe referensi digandakan, Anda harus mengulang array dan mengkloning setiap elemen secara manual.
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]); }
Saya jadi mengerti dari baris-baris berikut.
Salinan dangkal menyalin bidang tipe nilai objek (int, float, bool) ke objek target dan tipe referensi objek (string, kelas dll) disalin sebagai referensi di objek target. Dalam target referensi ini jenis akan menunjuk ke lokasi memori objek sumber.
Salinan yang dalam menyalin nilai objek dan tipe referensi ke dalam salinan objek objek yang lengkap yang baru. Ini berarti tipe nilai dan tipe referensi akan dialokasikan ke lokasi memori baru.
Menambahkan ke semua definisi di atas, satu salinan dalam yang lebih dan paling sering digunakan, ada di copy constructor (atau overloading assignment oprator) dari kelas.
Salinan dangkal -> adalah saat Anda tidak menyediakan pembuat salinan. Di sini, hanya objek yang disalin tetapi tidak semua anggota kelas disalin.
Salinan dalam -> adalah ketika Anda telah memutuskan untuk mengimplementasikan copy constructor atau tugas yang berlebihan di kelas Anda dan memungkinkan menyalin semua anggota kelas.
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
}
Copy constructor digunakan untuk menginisialisasi objek baru dengan objek yang dibuat sebelumnya dari kelas yang sama. Secara default kompiler menulis salinan yang dangkal. Salinan dangkal berfungsi dengan baik ketika alokasi memori dinamis tidak terlibat karena ketika alokasi memori dinamis terlibat maka kedua objek akan menunjuk ke lokasi memori yang sama di tumpukan, Oleh karena itu untuk menghapus masalah ini kami menulis salinan yang dalam sehingga kedua objek memiliki salinan atributnya sendiri dalam memori. Untuk membaca detail dengan contoh dan penjelasan lengkap, Anda bisa melihat artikel C ++ konstruktor .