إعادة تعريف الدوال (@Override)
جزء من قسم البرمجة كائنية التوجه في رحلة Java على Coddy. الدرس 22 من 87.
تجاوز method يسمح لفئة فرعية بتوفير تطبيقها الخاص لـ method تم تعريفه مسبقًا في فئتها parent. هكذا تُخصِّص الفئات الابنة behavior الموروث ليلائم احتياجاتها المحددة.
عندما تقوم overriding لـ method، فإن إصدار الفئة الفرعية يستبدل إصدار parent بالكامل بالنسبة إلى object من تلك الفئة الفرعية. يجب أن تحمل method الاسم نفسه والمعلمات نفسها مثل method الخاصة بـ parent، وأن يكون نوع الإرجاع نفسه (أو subtype منه) الخاص بـ parent:
public class Animal {
public void makeSound() {
System.out.println("Some generic sound");
}
}
public class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("Woof!");
}
}
public class Cat extends Animal {
@Override
public void makeSound() {
System.out.println("Meow!");
}
}تخبر التعليمة التوضيحية @Override الـcompiler بأنك تنوي تجاوز method في parent. ورغم أنها اختيارية، يُنصح بها بشدة لأن الـcompiler سيكتشف الأخطاء إذا أخطأتَ عن طريق الخطأ في تهجئة اسم method أو استخدمتَ معاملات غير صحيحة:
@Override
public void makeSound() { } // صحيح - يتحقق المترجم من هذا
public void makesound() { } // خطأ مطبعي! ينشئ دالة جديدة بدلاً من إعادة التعريفعندما تستدعي method تمت إعادة تعريفها، تنفّذ Java الإصدار الذي ينتمي إلى النوع الفعلي للكائن:
Dog dog = new Dog();
dog.makeSound(); // المخرجات: Woof!
Cat cat = new Cat();
cat.makeSound(); // المخرجات: Meow!تذكّر من الدرس السابق أنه يمكنك استخدام super.methodName() داخل method تمّت إعادة تعريفه إذا كنت لا تزال تريد تضمين behavior الخاص بـ parent إلى جانب كودك الجديد.
التحدي
سهللنَبْنِ نظام notification يوضّح كيف يمكن للفئات الفرعية تجاوز أساليب الفئة parent لتوفير سلوك متخصص خاص بها. سترى كيف تساعد التعليمة التوضيحية @Override في اكتشاف الأخطاء، وكيف يمكن لكل فئة فرعية تخصيص الأساليب الموروثة.
ستنشىء ثلاثة ملفات لتنظيم التعليمات البرمجية:
Notification.java: أنشئ فئةparentتمثّل إشعارًاgeneric. يجب أن تحتوي على:- حقل
privateلـmessageمن النوع (String) - مُنشئ
constructorيقبلmessage - أسلوب
getMessage()يعيدmessage - أسلوب
send()يطبع:Sending notification: [message]
- حقل
EmailNotification.java: أنشئ فئة فرعية تمتد منNotificationوتخصّص كيفية إرسالnotificationsعبرemail:- حقل
privateلـrecipient، أي عنوانemailمن النوع (String) - مُنشئ يأخذ كلًا من
messageوrecipient، باستخدامsuper(message)لجزء الفئةparent - تجاوز أسلوب
send()باستخدام التعليمة التوضيحية@Overrideلطباعة:Emailing [recipient]: [message]
- حقل
Main.java: وضّح كيف ينتج اسم الأسلوب نفسه سلوكًا مختلفًا اعتمادًا على نوعobject. ستتلقى مُدخلين:messageوعنوانemail. أنشئ كلاً منNotificationعادي وEmailNotificationباستخدامmessageنفسه، ثم استدعِsend()على كل منهما لرؤية المخرجات المختلفة.
ستتلقى مُدخلين: message من النوع (String) وعنوان email الخاص بـ recipient من النوع (String).
يجب أن يُظهر ناتجك سطرين — الأول من أسلوب send() في الفئة parent، ثم من الإصدار الذي تم تجاوزه في EmailNotification. يوضّح هذا كيف يتيح تجاوز الأساليب للفئات الفرعية استبدال السلوك الموروث بتنفيذ خاص بها.
جرّب بنفسك
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// قراءة المدخلات
String message = scanner.nextLine();
String recipient = scanner.nextLine();
// TODO: Create a Notification object with the message
// TODO: Create an EmailNotification object with the message and recipient
// TODO: Call send() on the Notification object
// TODO: Call send() on the EmailNotification object
}
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس البرمجة كائنية التوجه
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 عبر الإنترنت