معامل الـ instanceof
جزء من قسم البرمجة كائنية التوجه في رحلة Java على Coddy. الدرس 31 من 87.
أوضح الدرس السابق أن عملية downcasting قد تفشل مع ClassCastException إذا لم يكن الكائن فعليًا من النوع الذي تُجري التحويل إليه. يحلّ عامل التشغيل instanceof هذه المشكلة من خلال إتاحة التحقق من نوع الكائن قبل إجراء التحويل.
البنية بسيطة: تُرجع object instanceof ClassName القيمة true إذا كان الكائن مثيلًا من ذلك الصنف (أو من أي صنف فرعي له):
Animal animal = new Dog();
if (animal instanceof Dog) {
Dog dog = (Dog) animal;
dog.bark(); // من الآمن استدعاء الدوال الخاصة بـ Dog
}يمنع هذا الفحص أخطاء وقت التشغيل من خلال ضمان نجاح التحويل. يعيد العامل أيضًا true للأنواع الأصلية في التسلسل الهرمي:
Dog dog = new Dog();
System.out.println(dog instanceof Dog); // true
System.out.println(dog instanceof Animal); // true
System.out.println(dog instanceof Object); // trueمنذ Java 16، يمكنك الجمع بين الفحص والتحويل في خطوة واحدة باستخدام مطابقة الأنماط:
if (animal instanceof Dog dog) {
dog.bark(); // 'dog' تم تحويل نوعه بالفعل وجاهز للاستخدام
}تزيل هذه الصياغة الأنظف سطر التحويل المنفصل. لاحظ أن instanceof تُرجع false عند اختبارها مقابل null، لذا لا تحتاج إلى فحص منفصل للقيمة الفارغة.
التحدي
سهللنَبْنِ نظامًا لفحص المركبات يستخدم العامل instanceof للتعرّف بأمان على أنواع المركبات المختلفة والتعامل معها. ستنشئ تسلسلًا هرميًا للمركبات وتكتب تعليمات برمجية تتحقق من النوع الفعلي لكل مركبة قبل الوصول إلى ميزاتها المتخصصة.
ستنظّم تعليماتك البرمجية عبر أربعة ملفات:
Vehicle.java: أنشئ الفئة الأساسية التي تشترك فيها جميع المركبات. تحتوي كل مركبة على الحقلmodel(String). أدرج مُنشئًا لتهيئته، وطريقة getter هيgetModel()، وطريقةinspect()تطبع:Inspecting vehicle: [model]Car.java: أنشئ فئة تمتد من Vehicle. تحتوي Cars على الحقل الإضافيnumDoors(int). استخدمsuperلتهيئة الفئة الأصل. أضف طريقةcheckDoors()تطبع:[model] has [numDoors] doorsMotorcycle.java: أنشئ فئة أخرى تمتد من Vehicle. تحتوي Motorcycles على الحقلhasSidecar(boolean). أضف طريقةcheckSidecar()تطبع إما[model] has a sidecarأو[model] has no sidecarاعتمادًا على قيمة boolean.Main.java: هنا يصبحinstanceofأساسيًا! ستتلقى أربعة مدخلات: طراز السيارة، وعدد الأبواب، وطراز الدراجة النارية، وما إذا كانت تحتوي على عربة جانبية (true/false).أنشئ مصفوفة من مراجع
Vehicleتحتوي على Car وMotorcycle. ثم نفّذ حلقة عبر المصفوفة، ولكل مركبة:- استدعِ الطريقة الأساسية
inspect() - استخدم
instanceofللتحقق مما إذا كانت Car — وإذا كان الأمر كذلك، نفّذ downcast بأمان واستدعِcheckDoors() - استخدم
instanceofللتحقق مما إذا كانت Motorcycle — وإذا كان الأمر كذلك، نفّذ downcast بأمان واستدعِcheckSidecar()
- استدعِ الطريقة الأساسية
ستتلقى أربعة مدخلات: طراز السيارة (String)، وعدد الأبواب (int)، وطراز الدراجة النارية (String)، وhasSidecar (boolean).
يجب أن يُظهر ناتجك أربعة أسطر — لكل مركبة، سترى رسالة فحصها، تليها عملية التحقق الخاصة بنوعها. يضمن العامل instanceof أنك لا تستدعي طرق Car إلا على Cars فعلية، ولا طرق Motorcycle إلا على Motorcycles فعلية، مما يمنع حدوث ClassCastException!
جرّب بنفسك
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// قراءة المدخلات
String carModel = scanner.nextLine();
int numDoors = Integer.parseInt(scanner.nextLine());
String motorcycleModel = scanner.nextLine();
boolean hasSidecar = Boolean.parseBoolean(scanner.nextLine());
// TODO: إنشاء كائن Car باستخدام carModel و numDoors
// TODO: إنشاء كائن Motorcycle باستخدام motorcycleModel و hasSidecar
// TODO: إنشاء مصفوفة من مراجع Vehicle تحتوي على Car و Motorcycle
// TODO: التكرار عبر المصفوفة ولكل مركبة:
// 1. استدعاء الدالة inspect()
// 2. استخدام instanceof للتحقق مما إذا كانت Car، ثم إجراء downcast واستدعاء checkDoors()
// 3. استخدام instanceof للتحقق مما إذا كانت Motorcycle، ثم إجراء downcast واستدعاء checkSidecar()
}
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس البرمجة كائنية التوجه
1أساسيات الـ OOP
الملفات الخارجيةمقدمة في الـ OOPالفئات (Classes) مقابل الكائنات (Objects)الكلمة المفتاحية thisالدوال (Methods)الحقول (Attributes)دالة البناء (Constructor)تعدد أشكال دالة البناء (Constructor Overloading)مراجعة - آلة حاسبة بسيطة4الوراثة
الوراثة الأساسية (extends)الكلمة المفتاحية superإعادة تعريف الدوال (@Override)تسلسل المنشئات (Constructor Chaining)كلاس Objectالوراثة الأحادية ومتعددة المستوياتلماذا لا توجد وراثة متعددة للكلاساتمراجعة - هيكلية الموظفين7الدوال الخاصة وفئة Object
دالة toString()equals() و hashCode()دالة clone()compareTo() و Comparableواجهة Comparatorمراجعة - الترتيب المخصص2محددات الوصول والتغليف
نظرة عامة على مستويات الوصولدوال Getter و Setterإخفاء البياناتالكلمة المفتاحية finalمراجعة - مدير الحساب البنكي5تعدد الأشكال (Polymorphism)
أساسيات الـ Method Overloadingالـ Method Overriding (في وقت التشغيل)الـ Upcasting والـ Downcastingمعامل الـ instanceofالفئات والدوال المجردة (Abstract)مراجعة - حاسبة الأشكال8مفاهيم OOP المتقدمة
الـ Composition مقابل الـ Inheritanceالـ Aggregation مقابل الـ Compositionالفئات الداخلية والمتداخلة والمجهولة (Inner, Nested & Anonymous)الـ Enums ودوالهاالـ Records (Java 16+)الـ Sealed Classes (Java 17+)11أنماط التصميم - الجزء الأول
مقدمة في أنماط التصميمنمط Singletonنمط Factoryنمط Builderنمط Observerنمط Strategy3خصائص الفئة والعضو الساكن
المتغيرات الخاصة بالكائن مقابل المتغيرات الساكنةالدوال الساكنةالكتل البرمجية الساكنةالثوابت (static final)ملخص - العداد والأدوات المساعدة6الواجهات (Interfaces) والأصناف المجردة (Abstract Classes)
مقدمة في الواجهات (Interfaces)تنفيذ الواجهات (Interfaces)تنفيذ واجهات متعددةالـ Default و Static في الواجهاتالأصناف المجردة مقابل الواجهاتالواجهات الوظيفية (Functional Interfaces)مراجعة - نظام الدفع9الأنواع العامة (Generics)
مقدمة في الأنواع العامةالأصناف العامة (Generic Classes)الدوال العامة (Generic Methods)معاملات الأنواع المقيدةالرموز البديلة (?, extends, super)مراجعة - الحاويات العامة12أنماط التصميم - الجزء الثاني
نمط الأمرنمط المحولنمط المزيننمط طريقة القالبنمط الحالةنمط التركيبنمط المكررتدرّب بنفسك: مترجم Java عبر الإنترنت