Generics في Java: لماذا هي ضرورية وكيفية استخدامها

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

Generics في Java: لماذا هي ضرورية وكيفية استخدامها



Generics (الأدوية) هي إحدى الميزات الرئيسية في Java، التي ظهرت في الإصدار J2SE 5.0. إنها تسمح بإنشاء كلاسات وواجهات وطرق تعمل مع أنواع البيانات المحددة في وقت الاستدعاء. بدلاً من كتابة تطبيقات منفصلة لكل من Integer و String و Double، تكتب كودًا واحدًا عالميًا. في هذه المقالة، سنشرح لماذا نحتاج إلى Generics في Java، وكيفية استخدامها عمليًا، وما هي المخاطر التي يجب معرفتها.



لماذا نحتاج إلى Generics في Java؟



قبل ظهور Generics، كان المطورون يستخدمون Object لتخزين أي نوع. كان هذا يعمل، لكنه أدى إلى مشكلتين خطيرتين:



  • غياب التحقق من الأنواع في مرحلة الترجمة. كان بإمكانك وضع String عن طريق الخطأ في قائمة بدلاً من Integer، وكان الخطأ يظهر فقط أثناء تنفيذ البرنامج.
  • الحاجة إلى تحويل الأنواع بشكل صريح. في كل مرة تستخرج فيها عنصرًا من مجموعة، كان مطلوبًا تحويل: (String) list.get(0). هذا جعل الكود ضخمًا وخطيرًا.


تحل Generics كلتا المشكلتين. إنها تسمح للمترجم بالتحقق من صحة الأنواع وتنفيذ التحويل تلقائيًا. لنلقِ نظرة على مثال بسيط:



// بدون Generics (الطراز القديم)List list = new ArrayList();list.add("Hello");String s = (String) list.get(0); // يحتاج إلى تحويل صريح

// مع GenericsList<String> list = new ArrayList<>();list.add("Hello");String s = list.get(0); // لا حاجة للتحويل


أصبح الكود أكثر أمانًا وقابلية للقراءة. يتم اكتشاف خطأ النوع في مرحلة الترجمة، وليس في وقت التشغيل.



كيفية استخدام Generics: الهياكل الأساسية



1. كلاسات Generic



يمكنك تعريف كلاس يقبل معلمة نوع واحدة أو أكثر. غالبًا ما يُستخدم حرف واحد: T (Type)، E (Element)، K (Key)، V (Value).



public class Box<T> {    private T content;

public void put(T item) { this.content = item; }

public T get() { return content; }}

// الاستخدامBox<String> stringBox = new Box<>();stringBox.put("Java");String value = stringBox.get(); // تحويل تلقائي


يتم استبدال المعامل T بالنوع الفعلي عند إنشاء الكائن. يضمن المترجم أنه لا يمكن وضع Integer في Box<String>.



2. طرق Generic



يمكن أن تكون الطرق معممة أيضًا، حتى لو لم يكن الكلاس generic. يُشار إلى معامل النوع قبل نوع الإرجاع:



public class Utils {    public static <T> T getMiddle(T... args) {        return args[args.length / 2];    }}

// الاستدعاءString middle = Utils.<String>getMiddle("A", "B", "C");// أو ببساطة: Utils.getMiddle("A", "B", "C") — سيستنتج المترجم النوع


طرق Generic مفيدة للدوال المساعدة التي تعمل مع أنواع بيانات مختلفة.



3. الأنواع المقيدة (Bounded Type Parameters)



أحيانًا تحتاج إلى تقييد الأنواع التي يمكن استبدالها. على سبيل المثال، لجعل الطريقة تعمل فقط مع الأرقام:



public class Calculator {    public static <T extends Number> double sum(T a, T b) {        return a.doubleValue() + b.doubleValue();    }}

// يعمل مع Integer و Double و Float إلخ.double result = Calculator.sum(5, 10); // 15.0


الكلمة المفتاحية extends تعني أن T يجب أن يكون نوعًا فرعيًا من الكلاس المحدد (أو ينفذ واجهة).



Wildcards: الأنواع غير المعروفة



تُستخدم Wildcards (رموز البدل) عندما يكون النوع الدقيق غير معروف أو غير مهم. يُرمز إليها بعلامة الاستفهام ?. هناك ثلاثة أنواع: