Menu
CoddyTech

مقدمة في الأنواع العامة

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

تخيّل أنك بحاجة إلى إنشاء فئة تخزّن قيمة وتسترجعها لاحقًا. من دون الأنواع العامة، سيتعين عليك كتابة فئات منفصلة لكل نوع: واحدة لـ Integer، وواحدة لـ String، وواحدة لـ Double، وهكذا. يؤدي ذلك إلى تكرار الشيفرة وصعوبات في صيانتها.

تحل الأنواع العامة هذه المشكلة من خلال إتاحة كتابة أصناف وطرائق تعمل مع أي نوع، مع الحفاظ في الوقت نفسه على أمان الأنواع. تعرّف عنصرًا نائبًا (يُسمى مَعْلَمة النوع) يُستبدل بنوع فعلي عند استخدام الصنف:

// من دون الأنواع العامة - يستخدم Object، ويتطلب تحويل النوع
List list = new ArrayList();
list.add("Hello");
String s = (String) list.get(0);  // يلزم تحويل النوع يدويًا

// مع الأنواع العامة - آمن من حيث النوع، ولا يتطلب تحويل النوع
List<String> list = new ArrayList<String>();
list.add("Hello");
String s = list.get(0);  // لا يلزم تحويل النوع

تشير الأقواس الزاوية <T> إلى معامل نوع. عندما تكتب List<String>، فأنت تخبر المُصرّف أن هذه القائمة ستحتوي على سلاسل نصية فقط. إذا حاولت إضافة عدد صحيح، فسيكتشف المُصرّف الخطأ فورًا بدلًا من حدوث فشل أثناء وقت التشغيل.

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

challenge icon

التحدي

سهل

لننشئ نظام تخزين بسيطًا يوضّح قوة الأنواع العامة من خلال مقارنة الطريقة القديمة (باستخدام Object مع التحويل) بالطريقة الجديدة (باستخدام الأنواع العامة مع أمان الأنواع).

ستنشىء ثلاثة ملفات لترى الفرق بنفسك:

  • OldBox.java: أنشئ صنفًا يخزّن القيم بالطريقة السابقة للأنواع العامة. يجب أن يحتوي OldBox على حقل خاص content من النوع Object. أضف مُنشئًا يقبل Object ويخزّنه، وطريقة getContent() تُعيد Object. تعمل هذه الطريقة، لكنها تتطلب تحويلًا عند استرجاع القيم.
  • GenericBox.java: أنشئ الآن النسخة الحديثة الآمنة من ناحية الأنواع باستخدام الأنواع العامة. يجب أن يستخدم GenericBox مُعامل نوع T في تعريفه. ويحتاج إلى حقل خاص content من النوع T، ومُنشئ يقبل قيمة من النوع T، وطريقة getContent() تُعيد النوع T. لا حاجة إلى التحويل عند استخدام هذا الصنف!
  • Main.java: اعرض الطريقتين جنبًا إلى جنب. ستتلقى مُدخلين: كلمة (String) ورقمًا (عددًا صحيحًا).

    أولًا، استخدم الطريقة القديمة: أنشئ OldBox يخزّن الكلمة، ثم استرجعها بتحويلها إلى String واطبع: OldBox (with cast): [value]

    بعد ذلك، استخدم طريقة الأنواع العامة: أنشئ GenericBox<String> يخزّن الكلمة نفسها، واسترجعها دون تحويل، واطبع: GenericBox (no cast): [value]

    ثم اعرض عمل الأنواع العامة مع الأعداد الصحيحة: أنشئ GenericBox<Integer> يخزّن الرقم، واسترجعه، واطبع: GenericBox Integer: [value]

    أخيرًا، اطبع سطرًا فارغًا يتبعه: Type safety: Generics catch errors at compile time!

ستتلقى مُدخلين بالترتيب: كلمة (String) ورقمًا (عددًا صحيحًا على هيئة String، وستحوّله).

لاحظ الفرق الأساسي: مع OldBox، عليك تحويل النوع باستخدام (String) box.getContent() والأمل في أن يكون النوع صحيحًا. أما مع GenericBox، فيعرف المترجم النوع ولا حاجة إلى أي تحويل. هذه هي الفائدة الأساسية للأنواع العامة: أمان الأنواع دون عناء التحويل!

جرّب بنفسك

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String word = scanner.nextLine();
        int number = Integer.parseInt(scanner.nextLine());
        
        // TODO: أنشئ OldBox يخزّن الكلمة
        // استرجعها مع التحويل إلى String واطبع: "OldBox (with cast): [value]"
        
        // TODO: أنشئ GenericBox<String> يخزّن الكلمة
        // استرجعها دون تحويل النوع واطبع: "GenericBox (no cast): [value]"
        
        // TODO: أنشئ GenericBox<Integer> يخزّن العدد
        // استرجعه واطبع: "GenericBox Integer: [value]"
        
        // TODO: اطبع سطرًا فارغًا، ثم اطبع:
        // "Type safety: Generics catch errors at compile time!"
    }
}
quiz iconاختبر نفسك

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

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

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