سؤال

كنت أبحث عن بعض البرامج التعليمية التي تشرح عن جافا Cloneable, ، لكن لم تحصل على أي روابط جيدة ، وأصبح سعة المكدس أكثر وضوحًا على أي حال.

أود أن أعرف ما يلي:

  1. Cloneable يعني أنه يمكن أن يكون لدينا استنساخ أو نسخة من الكائنات ، من خلال تنفيذ Cloneable واجهه المستخدم. ما هي مزايا وعيوب القيام بذلك؟
  2. كيف يحدث الاستنساخ العودية إذا كان الكائن كائنًا مركبًا؟
هل كانت مفيدة؟

المحلول

أول شيء يجب أن تعرفه Cloneable هو - لا تستخدمه.

من الصعب جدًا تنفيذ الاستنساخ Cloneable صحيح ، والجهد لا يستحق ذلك.

بدلاً من ذلك استخدم بعض الخيارات الأخرى ، مثل Apache-Commons SerializationUtils (عقل عميق) أو BeanUtils (الضحلة الكاذب) ، أو ببساطة استخدم البناء.

انظر هنا للحصول على وجهات نظر جوش بلوش حول الاستنساخ مع Cloneable, ، وهو ما يفسر العديد من عيوب النهج. ((جوشوا بلوش كان موظف الشمس ، وقاد تطوير العديد من ميزات جافا.)

نصائح أخرى

الاستنساخ نفسه هو للأسف مجرد واجهة علامة ، أي أنه لا يحدد طريقة clone ().

ما هو ، هو تغيير سلوك الكائن المحمي. cclone () ، والتي ستلقي clonenotsupportedException للفئات التي لا تنفذ استنساخ ، وتؤدي نسخة ضحلة حكيمة للأعضاء للفئات التي تفعل.

حتى لو كان هذا هو السلوك الذي تبحث عنه ، فستظل بحاجة إلى تنفيذ طريقة Clone () الخاصة بك لجعلها علنية.

عند تنفيذ Clone () ، فإن الفكرة هي البدء بإنشاء الكائن بواسطة Super.clone () ، والذي يضمن أن يكون من الفئة الصحيحة ، ثم القيام بأي عدد إضافي من الحقول في حالة عدم وجود نسخة ضحلة انت تريد. سيكون استدعاء مُنشئ من clone () مشكلة لأن هذا من شأنه أن يكسر الميراث في حالة رغبة الفئة الفرعية في إضافة منطقها الإضافي القابل للاستنساخ ؛ إذا كان من الممكن استدعاء Super.clone () ، فستحصل على كائن من الفئة الخاطئة في هذه الحالة.

يتخطى هذا النهج أي منطق يمكن تعريفه في بنائك ، والذي يمكن أن يكون مشكلة.

هناك مشكلة أخرى وهي أن أي فئات فرعية تنسى تجاوز Clone () سترث تلقائيًا النسخة الضحلة الافتراضية ، والتي من المحتمل ألا تكون ما تريد في حالة حالة قابلة للتغيير (والتي سيتم مشاركتها الآن بين المصدر والنسخة).

معظم المطورين لا يستخدمون استنساخًا لهذه الأسباب ، ببساطة تنفيذ منشئ نسخ بدلاً من ذلك.

لمزيد من المعلومات والمخاطر المحتملة للاستنساخ ، أوصي بشدة بالكتاب Java الفعال من Joshua Bloch

  1. يستدعي الاستنساخ طريقة غير لغوية لبناء كائنات - بدون منشئات.
  2. يتطلب منك الاستنساخ أن تعامل بطريقة ما مع clonenotsupportedException - أو إزعاج رمز العميل لمعالجته.
  3. الفوائد صغيرة - ليس عليك فقط كتابة مُنشئ نسخ يدويًا.

لذلك ، استخدم بشكل قضائي. لا يمنحك فوائد كافية بالمقارنة مع الجهد الذي تحتاجه لتطبيقه على القيام بكل شيء بشكل صحيح.

الاستنساخ هو نموذج البرمجة الأساسية. حقيقة أن Java ربما نفذها بشكل سيء من نواح كثيرة لا تقلل على الإطلاق من الحاجة إلى الاستنساخ. ومن السهل تنفيذ الاستنساخ الذي سيعمل ولكنك تريد أن تعمل ، ضحلة ، عميقة ، مختلطة ، أيا كان. يمكنك حتى استخدام اسم Clone للوظيفة وعدم تنفيذ استنساخ إذا أردت.

لنفترض أن لدي فئات A و B و C ، حيث يتم اشتقاق B و C من A. إذا كان لدي قائمة من الكائنات من النوع A مثل هذا:

ArrayList<A> list1;

الآن ، يمكن أن تحتوي هذه القائمة على كائنات من النوع A أو B أو C. أنت لا تعرف نوع الكائنات. لذلك ، لا يمكنك نسخ القائمة مثل هذا:

ArrayList<A> list2 = new ArrayList<A>();
for(A a : list1) {
    list2.add(new A(a));
}

إذا كان الكائن بالفعل من النوع B أو C ، فلن تحصل على النسخة الصحيحة. وماذا لو كان A مجردة؟ الآن ، اقترح بعض الناس هذا:

ArrayList<A> list2 = new ArrayList<A>();
for(A a : list1) {
    if(a instanceof A) {
        list2.add(new A(a));
    } else if(a instanceof B) {
        list2.add(new B(a));
    } else if(a instanceof C) {
        list2.add(new C(a));
    }
}

هذه فكرة سيئة للغاية. ماذا لو قمت بإضافة نوع جديد مشتق؟ ماذا لو كانت B أو C في حزمة أخرى ولم تتمكن من الوصول إليها في هذه الفئة؟

ما تريد فعله هو:

ArrayList<A> list2 = new ArrayList<A>();
for(A a : list1) {
    list2.add(a.clone());
}

لقد أشار الكثير من الناس إلى أن تنفيذ استنساخ Java الأساسي يمثل مشكلة. ولكن ، يمكن التغلب عليها بسهولة بهذه الطريقة:

في الفئة أ:

public A clone() {
    return new A(this);
}

في الفئة ب:

@Override
public B clone() {
    return new B(this);
}

في الفصل ج:

@Override
public C clone() {
    return new C(this):
}

أنا لا أقوم بتنفيذ استنساخ ، فقط باستخدام نفس اسم الوظيفة. إذا كنت لا تحب ذلك ، قم بتسمية شيء آخر.

أ) لا توجد الكثير من مزايا الاستنساخ على مُنشئ النسخ. من المحتمل أن يكون أكبره هو القدرة على إنشاء كائن جديد من نفس النوع الديناميكي بالضبط (على افتراض أن النوع المعلن قابل للاستنساخ وله طريقة استنساخ عام).

ب) يقوم المستنسخ الافتراضي بإنشاء نسخة ضحلة ، وسيظل نسخة ضحلة ما لم يغير تنفيذ استنساخك. قد يكون هذا أمرًا صعبًا ، خاصة إذا كان لدى فصلك الحقول النهائية

Bozho على حق ، يمكن أن يكون من الصعب الحصول على استنساخ. مُنشئ النسخ/المصنع سيخدم معظم الاحتياجات.

ما هي عيوب الاستنساخ؟

الاستنساخ أمر خطير للغاية إذا كان الكائن الذي تقوم بنسخه لديه تكوين. تحتاج إلى التفكير في الآثار الجانبية المحتملة في هذه الحالة لأن الاستنساخ يخلق نسخة ضحلة:

دعك نقول أن لديك كائن واحد للتعامل مع معالجة DB ذات الصلة. قل ، هذا الكائن لديه Connection اعتراض كواحد من الممتلكات.

لذلك عندما يخلق شخص ما استنساخ originalObject, ، الكائن الذي يتم إنشاؤه ، دع القول ، cloneObject. هنا originalObject و cloneObject عقد نفس المرجع ل Connection هدف.

لنقول originalObject يغلق Connection كائن ، حتى الآن cloneObject لن يعمل لأن ال connection تمت مشاركة الكائن بينهما وتم إغلاقه من قبل originalObject.

قد تحدث مشكلة مماثلة إذا اتركك تقول إنك تريد استنساخ كائن يحتوي على ioStream كخاصية.

كيف يحدث الاستنساخ العودية إذا كان الكائن كائنًا مركبًا؟

يمكن استنساخ نسخة ضحلة. المعنى هو أن بيانات الكائن الأصلي والكائن المستنسخ ستشير إلى نفس المرجع/الذاكرة. على عكس حالة النسخ العميق ، يتم نسخ بيانات من ذكرى الكائن الأصلي إلى ذاكرة كائن استنساخ.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top