بشكل عام، إنشاء نسخة من كائن تعني إنشاء نسخة طبق الأصل من الكائن لها نفس القيم ونوع البيانات. ومن أجل القيام بذلك، إما نحتاج إلى إجراء نسخة ضحلة أو نسخة عميقة، بشكل عام، إذا تم تخصيص متغيرات بشكل ديناميكي، فمن الضروري عمل نسخة عميقة من أجل إنشاء نسخة من الكائن. في هذه المقالة، سنناقش مفهومي النسخة الضحلة والنسخة العميقة والفروق الرئيسية بينهما. دعونا أولاً نفهم معنى النسخة الضحلة والعميقة:
النسخة الضحلة
يتعامل النسخ الضحل مع المؤشرات وعناوين الذاكرة. بدلاً من إنشاء نسخة مستقلة جديدة من النسخة الأصلية التي يشير إليها المؤشر، فإنه ينسخ ببساطة المؤشر. لذلك، عندما نقوم بعمل نسخة من كيان ما لإنشاء كيانين أو أكثر من كيانين بحيث تنعكس التغييرات في كائن واحد على الكيانات الأخرى أيضًا. ويمكننا القول إننا قمنا بعمل نسخة ضحلة، عندما لا يحدث تخصيص ذاكرة جديدة أبدًا للكيانات الأخرى، ويتم نسخ المرجع فقط إلى الكيانات الأخرى. الكود التالي يستخدم لغة جافا ويوضح المقصود:
class ABC { int x = 30; // instance variable of the class ABC} public class ShallowCopyExample { public static void main(String argvs[]) // main method{ ABC obj1 = new ABC(); // creating an object of the class ABCABC obj2 = obj1; // it will copy the reference, not value obj2.x = 6;// printing the value of x using reference variable obj1 System.out.println("The value of x is: " + obj1.x); } }
المخرجات:
The value of x is: 6
توضيح: في المثال أعلاه، نقوم بالتعديل على قيمة “x” باستخدام المتغير المرجعي “obj2” ونعرض قيمة “x” باستخدام المتغير المرجعي “obj1”. في المخرجات، نرى القيمة المحدثة “6” وليس القيمة الأصلية “30”؛ وذلك لأن “obj1 و obj2” يشيران إلى نفس الموقع في الذاكرة. لذلك، مهما كان التحديث الذي نستخدمه للمتغير المرجعي “obj2″، ستنعكس التغييرات نفسها على المتغير المرجعي “obj1”.
نسخة عميقة
عندما نقوم بعمل نسخة من كيان ما لإنشاء كيانين أو أكثر من كيانين بحيث لا تنعكس التغييرات في كيان واحد على الكيانات الأخرى، فيمكننا القول إننا قمنا بعمل نسخة عميقة. في النسخة العميقة، يحدث تخصيص ذاكرة جديد للكيانات الأخرى، ولا يتم نسخ عنوان الذاكرة إلى الكيانات الأخرى، لكل كيان مرجع مستقل خاص به. المثال التالي بلغة جافا، يوضح المقصود بالنسخ العميق:
class ABC { int x = 30; // instance variable of the class ABC }public class DeepCopyExample { public static void main(String argvs[]) // main method{ ABC obj1 = new ABC(); // creating an object of the class ABCABC obj2 = new ABC(); // it will copy the reference, not value obj2.x = 6;// using the reference variable obj2 updating the value to 6 // printing the value of x using reference variable obj1System.out.println("The value of x is: " + obj1.x); } }
المخرجات:
The value of x is: 30
توضيح: في المثال أعلاه، نقوم بالتعديل على قيمة “x” باستخدام المتغير المرجعي “obj2” ونعرض قيمة “x” باستخدام المتغير المرجعي “obj1”. في المخرجات، نرى القيمة الأصلية “30”، وليس القيمة المحدّثة “6”؛ وذلك لأن “obj1 و obj2” يشيران إلى مواقع ذاكرة مختلفة. لذلك، مهما كان التحديث الذي نستخدمه للمتغير المرجعي “obj2″، لن ينعكس التعديل على المتغير المرجعي “obj1”.
الاختلافات بين النسخة الضحلة والنسخة العميق
بعد التعرف على النسخ الضحل والنسخ العميق، دعنا نرى الاختلافات بين النسخة الضحلة والنسخة العميقة:
النسخة الضحلة | النسخة العميقة |
إنه سريع، حيث لا يتم تخصيص ذاكرة جديدة. | إنه بطيء، حيث يتم تخصيص ذاكرة جديدة. |
التغييرات في كيان واحد تنعكس على الكيانات الأخرى. | لا تنعكس التغييرات في كيان واحد على الكيانات الأخرى. |
النسخة الضحلة أقل تكلفة على الذاكرة. | النسخة العميقة أعلى تكلفة على الذاكرة. |
الكائن المستنسخ والكائن الأصلي ليسا منفصلين. | الكائن المستنسخ والكائن الأصلي منفصلان. |