Menu
Coddy logo textTech
flag Ar iconالعربيةdown icon

الـ Upcasting والـ Downcasting

جزء من قسم البرمجة كائنية التوجه في رحلة Java على Coddy. الدرس 30 من 87.

في الدرس السابق، رأيت كيف يمكن لمتغير من النوع parent أن يحتفظ بكائن من النوع الابن: Animal myPet = new Dog(). يُسمّى هذا الإسناد upcasting، ويحدث تلقائيًا لأن Dog يكون دائمًا من النوع Animal.

Upcasting ينقل إلى أعلى تسلسل الوراثة. وهو ضمني وآمن دائمًا:

Dog dog = new Dog();
Animal animal = dog;  // Upcasting - تلقائي

عند إجراء upcast، لا يمكنك الوصول إلا إلى methods المعرّفة في الصنف parent. تصبح methods الخاصة بـ child مخفية، رغم أن الكائن لا يزال Dog في جوهره.

يتم Downcasting في الاتجاه المعاكس، إذ يحوّل مرجعًا إلى parent مرة أخرى إلى نوع child. يتطلب ذلك عملية cast صريحة لأن هذا ليس آمنًا دائمًا:

Animal animal = new Dog();  // التحويل لأعلى (Upcasting)
Dog dog = (Dog) animal;     // التحويل لأسفل - يتطلب تحويلاً صريحاً
dog.bark();                 // يمكننا الآن الوصول إلى دوال Dog

إن عملية Downcasting محفوفة بالمخاطر. إذا لم يكن الكائن في الواقع من النوع الذي تقوم بالتحويل إليه، فإن Java تطرح ClassCastException في وقت التشغيل:

Animal animal = new Cat();
Dog dog = (Dog) animal;  // يتم التجميع، ولكنه يتعطل أثناء وقت التشغيل!

لا يستطيع المُصرِّف اكتشاف هذا الخطأ لأنه لا يرى سوى الأنواع المُعلنة. لا يُعرف النوع الفعلي للكائن إلا عند تشغيل البرنامج. في الدرس التالي، ستتعلّم كيفية التحقّق بأمان من نوع كائن قبل إجراء Downcasting.

challenge icon

التحدي

سهل

لنَبْنِ نظامًا لمشغّل وسائط يوضّح عمليتَي upcasting وdowncasting عمليًا. ستنشئ تسلسلاً هرميًا لأنواع الوسائط، وتتدرّب على التحويل بين المراجع إلى parent وchild.

ستنظّم التعليمات البرمجية عبر أربعة ملفات:

  • Media.java: أنشئ الـ base class الذي تشترك فيه جميع أنواع الوسائط. يحتوي كل عنصر وسائط على title field من النوع String. أدرج constructor لتهيئته، وgetter method هي getTitle()، وmethod هي play() تطبع: Playing: [title]
  • Song.java: أنشئ class يمتد من Media. تحتوي الأغاني على artist field إضافي من النوع String. استخدم super لتهيئة parent. نفّذ Override لـ play() لتطبع: Playing song: [title] by [artist]. أضف method هي showArtist() تطبع: Artist: [artist]
  • Podcast.java: أنشئ class أخرى تمتد من Media. تحتوي ملفات Podcast الصوتية على episode field من النوع int. نفّذ Override لـ play() لتطبع: Playing podcast: [title] - Episode [episode]. أضف method هي showEpisode() تطبع: Episode: [episode]
  • Main.java: وضّح عمليتَي upcasting وdowncasting باستخدام أنواع الوسائط لديك. ستتلقى أربعة inputs: عنوان أغنية، واسم artist، وعنوان Podcast، ورقم episode.

    أولًا، أنشئ Song ونفّذ له upcast إلى مرجع Media. استدعِ play() على هذا المرجع لرؤية polymorphism وقت التشغيل أثناء العمل.

    بعد ذلك، نفّذ downcast لمرجع Media هذا مجددًا إلى Song، واستدعِ showArtist() للوصول إلى method الخاصة بالـ child.

    ثم أنشئ Podcast ونفّذ له upcast إلى مرجع Media. استدعِ play() على هذا المرجع.

    أخيرًا، نفّذ downcast لمرجع Media هذا مجددًا إلى Podcast، واستدعِ showEpisode().

ستتلقى أربعة inputs: عنوان الأغنية (String)، واسم artist (String)، وعنوان Podcast (String)، ورقم episode (int).

يجب أن يعرض output أربعة أسطر — سطران للأغنية (ناتج play ومعلومات artist) وسطران لـ Podcast (ناتج play ومعلومات episode). لاحظ كيف يتيح لك upcasting التعامل مع أنواع الوسائط المختلفة بطريقة موحّدة، بينما يتيح لك downcasting الوصول إلى ميزاتها الفريدة!

جرّب بنفسك

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // قراءة المدخلات
        String songTitle = scanner.nextLine();
        String artistName = scanner.nextLine();
        String podcastTitle = scanner.nextLine();
        int episodeNumber = scanner.nextInt();
        
        // TODO: إنشاء كائن Song وإجراء upcast له إلى مرجع Media
        
        // TODO: استدعاء play() على مرجع Media (يوضح مفهوم polymorphism)
        
        // TODO: إجراء downcast لمرجع Media وإعادته إلى Song
        
        // TODO: استدعاء showArtist() على مرجع Song
        
        // TODO: إنشاء كائن Podcast وإجراء upcast له إلى مرجع Media
        
        // TODO: استدعاء play() على مرجع Media
        
        // TODO: إجراء downcast لمرجع Media وإعادته إلى Podcast
        
        // TODO: استدعاء showEpisode() على مرجع Podcast
    }
}
quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس البرمجة كائنية التوجه

تدرّب بنفسك: مترجم Java عبر الإنترنت