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 (رموز البدل) عندما يكون النوع الدقيق غير معروف أو غير مهم. يُرمز إليها بعلامة الاستفهام ?. هناك ثلاثة أنواع:
المدونات
توصيات الكتب
اقرأ أيضًا