سؤال

لماذا لا تدعم Java مُنشئ النسخ كما هو الحال في C++؟

هل كانت مفيدة؟

المحلول

جافا تفعل ذلك.لا يتم استدعاؤها ضمنيًا كما هو الحال في لغة C++ وأظن أن هذا هو سؤالك الحقيقي.

أولاً، مُنشئ النسخ ليس أكثر من:

public class Blah {
  private int foo;

  public Blah() { } // public no-args constructor
  public Blah(Blah b) { foo = b.foo; }  // copy constructor
}

الآن سوف يقوم C++ باستدعاء مُنشئ النسخة ضمنيًا ببيان مثل هذا:

Blah b2 = b1;

الاستنساخ/النسخ في هذه الحالة ليس له أي معنى في Java لأن كل b1 وb2 عبارة عن مراجع وليست كائنات ذات قيمة كما هي في C++.في لغة C++، يقوم هذا البيان بإنشاء نسخة من حالة الكائن.في Java، يقوم ببساطة بنسخ ملف مرجع.لا يتم نسخ حالة الكائن، لذا فإن استدعاء مُنشئ النسخ ضمنيًا ليس له أي معنى.

وهذا كل ما في الأمر حقًا.

نصائح أخرى

من بروس إيكل:

لماذا يعمل [منشئ النسخ] في لغة C++ وليس في Java؟

يعد مُنشئ النسخ جزءًا أساسيًا من C ++ ، لأنه يقوم تلقائيًا بنسخة محلية من كائن.ومع ذلك ، يثبت المثال أعلاه أنه لا يعمل لدى Java.لماذا؟في Java ، يكون كل ما نتلاعب به هو مقبض ، بينما في C ++ يمكنك الحصول على كيانات تشبه المقبض ويمكنك أيضًا المرور حول الكائنات مباشرة.هذا ما هو مُنشئ نسخ C ++ لـ:عندما تريد أن تأخذ كائنًا وتمريره بالقيمة ، وبالتالي تكرار الكائن.لذلك فهو يعمل بشكل جيد في C ++ ، ولكن يجب أن تضع في اعتبارك أن هذا المخطط يفشل في Java ، لذلك لا تستخدمه.

(أوصي بقراءة الصفحة بأكملها - في الواقع، ابدأ هنا بدلاً من.)

وأعتقد أن الجواب على هذا هو مثيرة جدا للاهتمام.

لواحد، وأعتقد أن في جاوة جميع الكائنات على كومة، وبينما لم يكن لديك مؤشرات، لديك "المراجع". المراجع لها symantics نسخة وجافا بتتبع حساب مرجع داخليا بحيث جمع القمامة بها يعرف ماذا يكون آمنة للتخلص منها.

ومنذ كنت فقط كائنات الوصول من خلال المراجع copyable، يتم تقليل العدد الفعلي المرات التي تحتاج إلى نسخ كائن إلى حد كبير (على سبيل المثال، في C ++ فقط تمرير كائن إلى وظيفة (من حيث القيمة) النتائج في الأشياء الجديدة التي يجري نسخة شيدت ، في جاوة يتم تمريرها فقط الإشارة إلى كائن). المصممين ربما أحسب أن استنساخ () سيكون كافيا للاستخدامات المتبقية.

وهذا هو مجرد رأيي (وأنا متأكد من أن هناك إجابة لها ما يبررها)

ومنشئات نسخة في C ++ هي مفيدة في المقام الأول عندما تقوم بإرسال أو العودة مثيلات الفئات من حيث القيمة، لأن ذلك هو عندما يتم تنشيط منشئ نسخة بشفافية.

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

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

وتخمين ما أحسب يمكنك ان تجعل مجرد طريقة استنساخ () بدلا من ذلك؟

وانها نوع من يفعل. عندما تكون نسخ الضحلة بخير لديك [استنساخ ()] (<لأ href = "http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Object.html#clone ()) "يختلط =" نوفولو noreferrer "> http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Object.html#clone ()) و عندما لا تكون لديك لتنفيذ نسخة عميق تماما مثل C ++.

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

وأنا لست كثير من C ++ مبرمج، لكنني لا يبدو أن نتذكر قاعدة حول "ثلاثة الاصدقاء" - نسخ منشئ، عامل التعيين، والمدمر. إذا كان لديك واحدة، فإنك على الأرجح بحاجة إلى كل ثلاثة.

وهكذا ربما دون المدمر في اللغة، وأنهم لا يريدون لتشمل منشئ نسخة؟ مجرد تخمين.

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

في C ++، منشئ نسخة الافتراضي هو نسخة الضحلة عضوا الحكمة. إذا تملك فئة الذاكرة المخصصة على كومة (عن طريق مؤشر الخام)، وهذا سوف يسبب نسخة لتبادل الداخلية مع الأصل، وهي ليست على ما تريد.

وتخيل للحظة أن كان جافا هذا السلوك. أي فئة يحتوي على حقول التي هي الكائنات (قراءة: أساسا كل واحد منهم) لن يكون سلوك خاطئ، وكنت بحاجة لتجاوز ذلك بنفسك. 99٪ من الحالات، لم تقم بحفظ أي شخص أي مشكلة. وعلاوة على ذلك، قمت بإنشائها مجرد فخ خفية لنفسك - تخيل أنك نسيت بطريق الخطأ لتجاوز منشئ نسخة الافتراضي. إذا تم إنشاؤها بشكل افتراضي، ومحاولة استخدام ذلك، فإن المترجم لا يشكون في كل شيء، ولكن البرنامج يسيئون التصرف في وقت التشغيل.

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

وكائنات انك تملك، والأشياء التي كنت تحمل ما يشير إلى أنك في حاجة إليها، ولكن نحن لسنا مسؤولين عنها، هي نفسها - حقول فقط. الملكية والاقتراض ليست مفاهيم الدرجة الأولى. لالكائنات التي تملك، وكنت ترغب في عمق نسخها (إلا انهم غير قابل للتغيير، وفي هذه الحالة يجب أن لا يكلف نفسه عناء)، والكائنات التي مجرد عقد إشارة إلى، وتريد لنسخ المرجع.

وأنا أزعم أن منشئ نسخة من شأنه فقط بغفلة-نسخ عميقة كل شيء لا تكون مناسبة لفئات كثيرة، إما. أكثر بالتأكيد من الضحلة نسخ افتراضيا، وإن كان.

جافا يملك نسخة منشئ
ملحوظة: بدلاً من العرض التوضيحي d2 = العرض التوضيحي الجديد (d1) ،يمكنك كتابة العرض التوضيحي d2=d1
الفرق الرئيسي ب / ث اثنين
العرض التوضيحي d2 = العرض التوضيحي الجديد (d1) يعني أن يتم إنشاء كائن جديد ويتم تخصيصه ذاكرة ولكن
العرض التوضيحي d2=d1 يتضمن إنشاء متغير مرجعي فقط والذي يستخدم نفس عنوان الذاكرة للكائن د1 وبالتالي د2 لم تخصيص الذاكرة الفاصلة.

بناء جملة منشئ النسخ:
انظر أدناه المثال الأول منشئ النسخ سهل للغاية :))
classname(int datafield) // مُنشئ بسيط
{
this.datafield=datafield;
}

اسم الفئة (كائن اسم الفئة)
{
datafield=object.datafield;//انظر المثال أدناه
}
الآن للاتصال
{

classname obj=new classname();

اسم الفئة آخرObject = obj؛ // أو اسم الفئة AnotherObject = اسم فئة جديد (obj)

}

 class demo
{
    private int length;

    private int breadth;

    private int radius;

    demo(int x,int y)

    {
        length=x;
        breadth=y;
    }
    int area()
    {
        return length*breadth;
    }

    //Copy Constructor
    demo(demo obj)
    {
        length=obj.length;
        breadth=obj.breadth;
    }


    public static void main(String args[])
    {
        demo d1=new demo(5,6);
        demo d2=new demo(d1);//Invokes Copy Constructure
        System.out.println("Area for d1 object="+d1.area());
        System.out.println("Area for d2 object="+d2.area());

    }
}

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