الفئات العامة (Generic Classes)
الفئات العامة (Generic Classes)
الفئة العامة هي فئة مُعرَّفة بمُعامل نوع (type parameter). بدلًا من تحديد نوع ثابت مثل String أو Integer، تُعلن عن عنصر نائب يملأه المُستدعي عند الاستخدام. يتحقّق المُترجم بعد ذلك من صحة كل استخدام، مُزيلًا أخطاء التحويل التي كانت شائعة قبل Java 5.
لماذا نكتب فئة عامة؟
افترض أنّك تحتاج إلى حاوية بسيطة تحمل قيمة واحدة وتُعيدها. بدون الجنيريكس أمامك خياران سيئان: كتابة فئة مستقلة لكل نوع (StringBox، IntBox، …) أو استخدام Object مع التحويل اليدوي في كل مرة. كلاهما مُرهِق. الفئة العامة تحلّ المشكلتين دفعةً واحدة.
الإعلان عن فئة عامة
ضَع قائمة مُعامِلات النوع — اسم واحد أو أكثر بين أقواس الزاوية — مباشرةً بعد اسم الفئة:
T مجرّد اسم؛ بالاتفاق تُستخدم أحرف كبيرة مفردة: T للنوع، E للعنصر، K وV للمفتاح والقيمة، R لنوع الإرجاع. يستبدل المُترجم T بما يُوفّره المُستدعي.
استخدام الفئة العامة
عند موقع الاستدعاء تُوفّر وسيطة النوع بين أقواس الزاوية عند إنشاء الكائن:
<>: منذ Java 7 يمكنك حذف وسيطة النوع على الجانب الأيمن من الإعلان — يستنتجها المُترجم من الجانب الأيسر. استخدم دائمًا new Box<>(...) عوضًا عن new Box<String>(...) لتقليل التكرار.
مُعامِلات نوع متعددة
يمكن للفئة أن تحمل أكثر من مُعامِل نوع. مثال كلاسيكي هو الزوجية التي تحمل قيمتين مستقلتين:
الفئات العامة وأعضاؤها
يمكن لكل تابع نموذجي (instance method) داخل الفئة العامة استخدام مُعامِلات النوع الخاصة بمستوى الفئة. يعمل مُعامِل النوع كأنّه نوع ملموس لكامل النموذج:
الأعضاء الساكنة لا تستطيع استخدام مُعامِل نوع الفئة
private static T cache; داخل فئة عامة. إن احتجت إلى أداة مساعدة ساكنة عامة، أعلن عن تابع عام بدلًا من ذلك (موضوع الدرس التالي).
الأنواع الخام — ما يجب تجنّبه
إن استخدمت فئة عامة دون وسيطة نوع، تسمح Java بذلك لأسباب التوافق مع الإصدارات القديمة، لكنك تفقد كل أمان النوع:
لا تستخدم الأنواع الخام في الكود الجديد. وُجدت فقط للتعامل مع مكتبات ما قبل Java 5. ستُنبّه بيئات التطوير الحديثة عليها بتحذيرات وستعدّها أدوات التحليل الساكن أخطاءً.
تطبيق متكامل — نوع Result العام
إليك نمطًا واقعيًا: Result<T> يُغلّف إمّا قيمة نجاح أو رسالة خطأ، دون إطلاق استثناءات:
<T> (تابع عام) لأن السياق الساكن لا يستطيع الوصول إلى T الخاصة بالفئة. النقطة المهمة هنا هي كيف يتدفّق مُعامِل النوع على مستوى الفئة بشكل طبيعي عبر جميع التوابع النموذجية.
خلاصة
- أعلن عن مُعامِلات النوع بعد اسم الفئة:
class Foo<T>. - استخدم عامل الماسة
<>على الجانب الأيمن ليستنتج المُترجم النوع. - يُسمح بمُعامِلات متعددة:
class Pair<A, B>. - يستطيع أعضاء النموذج استخدام مُعامِل النوع بحرية؛ الأعضاء الساكنة لا تستطيع ذلك.
- تجنّب الأنواع الخام — قدّم دائمًا وسيطة نوع.