JavaRush /مدونة جافا /Random-AR /مثيل المشغل في جافا

مثيل المشغل في جافا

نشرت في المجموعة
مرحبًا! سنتحدث اليوم عن مثيل عامل التشغيل، ونلقي نظرة على أمثلة لاستخدامه ونتطرق إلى بعض النقاط المتعلقة بتشغيله :) في المستويات الأولى من JavaRush، كنت قد واجهت هذا العامل بالفعل. هل تتذكر لماذا هو مطلوب؟ إذا لم يكن الأمر كذلك، فلا يهم، دعونا نتذكر معًا. هناك حاجة إلى عامل تشغيل المثيل للتحقق مما إذا كان الكائن المشار إليه بواسطة المتغير X قد تم إنشاؤه بناءً على فئة Y. يبدو الأمر بسيطًا. لماذا رجعنا لهذا الموضوع؟ بادئ ذي بدء، لأنك الآن على دراية جيدة بآلية الميراث في Java ومبادئ OOP الأخرى. سيكون موضوع المثيل أكثر وضوحًا وسننظر في حالات الاستخدام الأكثر تقدمًا. يذهب! كيف يعمل عامل التشغيل Instanceof - 1ربما تتذكر أن مثيل عامل التشغيل يُرجع صحيحًا إذا كان الاختبار صحيحًا، أو خطأ إذا كانت النتيجة خاطئة. وبالتالي، فإنه يوجد غالبًا في أنواع مختلفة من ظروف الاختبار ( if…else). لنبدأ بأمثلة أبسط:
public class Main {

   public static void main(String[] args) {

       Integer x = new Integer(22);

       System.out.println(x instanceof Integer);
   }
}
ما رأيك سيتم إخراج إلى وحدة التحكم؟ حسنًا، الأمر واضح هنا :) الكائن хعبارة عن عدد صحيح، وبالتالي ستكون النتيجة صحيحة . إخراج وحدة التحكم: صحيح فلنحاول التحقق مما إذا كان ينتمي، على سبيل المثال، إلى السلسلة:
public class Main {

   public static void main(String[] args) {

       Integer x = new Integer(22);

       System.out.println(x instanceof String);// error!
   }
}
لقد تلقينا خطأ. وانتبه: أصدره المترجم حتى قبل تنفيذ الكود! لقد رأى على الفور أن العدد الصحيح والسلسلة لا يمكن تحويلهما تلقائيًا إلى بعضهما البعض وليس لهما علاقات ميراث. ولذلك، لن يتم إنشاء كائن فئة عدد صحيح من السلسلة. وهذا مناسب ويساعد على تجنب الأخطاء الغريبة أثناء تنفيذ البرنامج، لذلك ساعدنا المترجم هنا :) الآن دعونا نحاول إلقاء نظرة على أمثلة أكثر تعقيدًا. وبما أننا ذكرنا الميراث، فلنعمل مع نظام الفئات الصغيرة هذا:
public class Animal {

}

public class Cat extends Animal {

}

public class MaineCoon extends Cat {

}
نحن نعلم بالفعل كيف يتصرف المثيل عندما نتحقق مما إذا كان الكائن ينتمي إلى فئة ما في الوضع العادي، ولكن ماذا يحدث إذا أضفنا علاقة بين الوالدين والطفل هنا؟ كيف يعمل عامل التشغيل Instanceof - 2 على سبيل المثال، في رأيك، ما الذي سينتج عن الفحص التالي:
public class Main {

   public static void main(String[] args) {

       Cat cat = new Cat();

       System.out.println(cat instanceof Animal);

       System.out.println(cat instanceof MaineCoon);

   }
}
الإخراج: صحيح خطأ السؤال الرئيسي الذي يجب الإجابة عليه هو كيف يمكن لمثيل المثيل أن يفك تشفير مفهوم "كائن تم إنشاؤه بناءً على فئة"؟ ونتيجة لذلك، حصلنا عليه Сat instanceof Animal == true، ولكن يمكن العثور على خطأ في مثل هذه الصياغة. لماذا يتم إنشاء هذا الكائن Catبناءً على الفصل Animal؟ أليس يتم إنشاؤه فقط على أساس فئته الخاصة؟ الجواب بسيط للغاية، وربما تكون قد عرفته بالفعل. تذكر الترتيب الذي يتم به استدعاء المُنشئين وتهيئة المتغيرات عند إنشاء كائن. لقد تناولنا هذا الموضوع بالفعل في المقالة حول مُنشئ الفصل . وإليك مثال من تلك المحاضرة:
public class Animal {

   String brain = "The initial value of brain in the Animal class";
   String heart = "The initial value of heart in the Animal class";

   public static int animalCount = 7700000;

   public Animal(String brain, String heart) {
       System.out.println("The constructor of the Animal base class is being executed");
       System.out.println("Have the variables of the Animal class already been initialized?");
       System.out.println("The current value of the static variable animalCount = " + animalCount);
       System.out.println("Current value of brain in class Animal = " + this.brain);
       System.out.println("Current value of heart in class Animal = " + this.heart);

       this.brain = brain;
       this.heart = heart;
       System.out.println("Animal base class constructor completed!");
       System.out.println("Current value of brain = " + this.brain);
       System.out.println("Current value of heart = " + this.heart);
   }
}

class Cat extends Animal {

   String tail = "The initial value of tail in the Cat class";

   static int catsCount = 37;

   public Cat(String brain, String heart, String tail) {
       super(brain, heart);
       System.out.println("The constructor of the Cat class has started (the Animal constructor has already been executed)");
       System.out.println("The current value of the static variable catsCount = " + catsCount);
       System.out.println("Current value tail = " + this.tail);
       this.tail = tail;
       System.out.println("Current value tail = " + this.tail);
   }

   public static void main(String[] args) {
       Cat cat = new Cat("Brain", "Heart", "Tail");
   }
}
وإذا قمت بتشغيله في IDE، فستبدو مخرجات وحدة التحكم كما يلي: مُنشئ الفئة الأساسية Animal قيد التشغيل. هل تمت تهيئة متغيرات فئة Animal بالفعل؟ القيمة الحالية للمتغير الثابت AnimalCount = 7700000 القيمة الحالية للدماغ في فئة الحيوان = القيمة الأولية للدماغ في فئة الحيوان القيمة الحالية للقلب في فئة الحيوان = القيمة الأولية للقلب في فئة الحيوان مُنشئ فئة الحيوان الأساسية أكملت عملها! القيمة الحالية للدماغ = الدماغ القيمة الحالية للقلب = القلب بدأ مُنشئ فئة Cat العمل (تم تنفيذ مُنشئ الحيوان بالفعل) القيمة الحالية للمتغير الثابت القطط عدد = 37 القيمة الحالية للذيل = القيمة الأولية للذيل في فئة القط القيمة الحالية للذيل = الذيل هل تتذكر الآن؟ :) مُنشئ الفئة الأساسية، إذا كان موجودًا، يتم استدعاؤه أولاً دائمًا عند إنشاء أي كائن. يتبع Instanceof هذا المبدأ عندما يحاول تحديد ما إذا كان الكائن قد تم Аإنشاؤه من فئة أم لا Б. إذا تم استدعاء مُنشئ الفئة الأساسية، فلا يمكن أن يكون هناك شك. مع الاختيار الثاني، كل شيء أبسط:
System.out.println(cat instanceof MaineCoon);
MaineCoonلم يتم استدعاء المنشئ عند الإنشاء Cat، وهو أمر منطقي. MaineCoonفهو في النهاية نسل Catوليس سلفا. لكنها Catليست قالبا ل. حسنًا، يبدو هذا واضحًا. ماذا سيحدث لو فعلنا هذا:
public class Main {

   public static void main(String[] args) {

       Cat cat = new MaineCoon();

       System.out.println(cat instanceof Cat);
       System.out.println(cat instanceof MaineCoon);


   }
}
حسنًا... هذا أكثر تعقيدًا. دعونا نحاول التفكير. لدينا متغير من النوع Cat، وقمنا بتخصيص كائن من نوعه له MaineCoon. بالمناسبة، لماذا يعمل هذا حتى؟ هل من الممكن أن تفعل هذا؟ يستطيع. بعد كل شيء، أي مين كون هو قطة. إذا لم يكن الأمر واضحًا تمامًا، فتذكر المثال بامتدادات النوع البدائي:
public class Main {

   public static void main(String[] args) {

       long x = 1024;

   }
}
الرقم 1024 قصير : يمكن وضعه بسهولة في المتغير الطويل ، لأن عدد البايتات يكفي له (تذكر المثال مع الدمى المتداخلة؟). يمكن دائمًا تعيين كائن فرعي لمتغير سلف. فقط تذكر هذا الآن، وفي المحاضرات القادمة سنقوم بتحليل هذه العملية بشكل أكبر. فماذا سينتج عن مثالنا؟
Cat cat = new MaineCoon();
System.out.println(cat instanceof Cat);
System.out.println(cat instanceof MaineCoon);
ما الذي سيتحقق منه المثيل: متغير فئتنا Catأو كائن فئتنا MaineCoon؟ في الواقع، الجواب على هذا السؤال بسيط. تحتاج فقط إلى قراءة تعريف عامل التشغيل الخاص بنا مرة أخرى: هناك حاجة إلى عامل تشغيل مثيل للتحقق مما إذا كان الكائن المشار إليه بواسطة المتغير قد تم Xإنشاؤه بناءً على فئة ما Y. يتحقق عامل التشغيل من أصل الكائن، وليس المتغير. لذلك، في المثال، سيتم عرضه صحيحًا في وحدة التحكم في كل مرة : لدينا كائن من النوع MaineCoon. وبطبيعة الحال، تم إنشاؤه بناءً على الفصل الدراسي MaineCoon، ولكن أيضًا بناءً على الفصل الأصلي Catأيضًا!
تعليقات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION