مقدمة عن الGenerics في الجافا
بسم الله الرحمن الرحيم
السلام عليكم ورحمة الله وبركاته
سنتطرق في هذا الموضوع للGenerics (الميثودز العامة)، مقدمة عن ماهي، ما فائدتها، وكيفية استخدامها بالجافا.
مقدمة
في أي مشروع او برنامج تعمل عليه بالجافا، ستواجه مشاكل في الcompiling وستواجه الكثير من الexceptions. لذلك من مهام المسؤولين عن لغة الجافا أن يساعدوا المطورين في مواجهة هذه الأخطاء والتقليل منها بقدر المستطاع.
أحد أهم ما قدم في تحديث الJava 1.5 كان هو الGenerics. طريقة جديدة لتجنب مشاكل قد تواجهك في تطويرك لمشروعك.
فائدتها
ماهي هذه المشاكل التي قد تواجهك؟
أكبر مشكلة أتت هذه الGenerics لحلها هي الأنواع المستخدمة في المجموعات (Collections)، كالArrayList, LinkedLists الخ..
المشكلة تكمن (ما قبل Java 1.5) في النوع المستخدم لعناصر الCollection غير قابل للتحديد من قبل الكلاس، لذلك عندما يأتي المستخدم وينشئ اوبجكت من هذا الكلاس ويستخدم الميثودز الخاصة به، قد يستخدم cast خاطئ لعنصر في collection معينة، فمثلا قد يعمل كاست لعنصر (Integer) ك(String)
مثلا:
static void expurgate(Collection c) {
for (Iterator i = c.iterator(); i.hasNext(); )
if (((String) i.next()).length() == 4)
i.remove();
}
في المثال السابق، الميثود expurgate ستفترض دائما أن العناصر المقروءة من المجموعة c هي Strings. بالتالي في حالة أن اخطأ المستخدم بادخال مجموعة تحتوي على عناصر من نوع آخر سنواجه Casting exceptions.
سنعدل المثال السابق باستخدام الgenerics لنرى كيف نتفادى مشاكل الcasting:
static void expurgate(Collection<String> c) {
for (Iterator<String> i = c.iterator(); i.hasNext(); )
if (i.next().length() == 4)
i.remove();
}
لاحظ تحديد نوع العناصر في الانبوت لتكون من نوع String، ولاحظ أيضا عدم الحاجة للCast داخل اللوب، وبذلك نلغي احتمالية حدوث Cast exceptions.
سنتحدث عن الSyntax وأنواع الجينات لاحقا.
لكن لنخلص أهم فوائد الGenerics أولا:
- مساعدة الCompiler في تحديد الأخطاء وقت الCompilation
- التخلص من الCasts
- مساعدة المطورين على كتابة ميثودز عامة، وعدم الحاجة لكتابة أكثر من ميثود لاستقبال أكثر من نوع من الparameters.
طريقة استخدامها
لاشك أنك لاحظت أن الGenerics تستعمل نوع خاص من الأقواس <> (الدايموند)، هذا صحيح. يجب استعمال هذه الأقواس عند الرغبة باستخدام الGenerics في كتابة الكلاسات وعند الرغبة بانشاء Objects منها.
لنأخذ مثال كلاس الArrayList الموجود في مكاتب الجافا الافتراضية، مكتوب بالشكل التالي:
public class ArrayList<E> implements List<E> .... {
// Constructor
public ArraList() { ...... }
// Public methods
public boolean add(E e) { ...... }
public void add(int index, E element) { ...... }
public boolean addAll(int index, Collection<? extends E> c)
public abstract E get(int index) { ...... }
public E remove(int index)
.......
}
نلاحظ استخدام الGeneric من نوع <E> للاستغناء عن تخصيص نوع معين لعناصر الArrayList وترك الخيار للمستخدم.
لإنشاء اوبجكت ArrayList:
ArrayList<Integer> lst1 = new ArrayList<Integer>(); // E substituted with Integer
lst1.add(0, new Integer(88));
lst1.get(0);
ArrayList<String> lst2 = new ArrayList<String>(); // E substituted with String
lst2.add(0, "Hello");
lst2.get(0);
قمنا هنا بانشاء اوبجكتين من الArrayList الأول بعناصر من نوع Integer والثاني بعناصر من نوع String، وذلك باستخدام الكلاس والميثودز نفسها.
إذا اردت انشاء كلاس خاص فيك وربط الاوبجكت بنوع عام (وترك التخصيص للمستخدم) يمكنك عمل التالي:
public class GenericBox<E> {
// Private variable
private E content;
// Constructor
public GenericBox(E content) {
this.content = content;
}
public E getContent() {
return content;
}
public void setContent(E content) {
this.content = content;
}
public String toString() {
return content + " (" + content.getClass() + ")";
}
}
نلاحظ مرة أخرى استخدام الGeneric من نوع <E> للاستغناء عن تخصيص نوع معين وترك الخيار للمستخدم.
لاحظ في ميثود الtoString() قمنا باستدعاء الكلاس الخاص بالGeneric (أيا كان) لطباعته.
لإنشاء أوبجكت من الكلاس السابق:
public class TestGenericBox {
public static void main(String[] args) {
GenericBox<String> box1 = new GenericBox<String>("Hello");
String str = box1.getContent();
System.out.println(box1);
GenericBox<Integer> box2 = new GenericBox<Integer>(123); // autobox int to Integer
int i = box2.getContent();
System.out.println(box2);
GenericBox<Double> box3 = new GenericBox<Double>(55.66); // autobox double to Double
double d = box3.getContent();
System.out.println(box3);
}
}
قمنا بالكود السابق انشاء 3 اوبجكتات من الكلاس GenericBox بانواع مختلفة، وأيضا باستخدام الكلاس والمثودز نفسها .
أنواعها
للGenerics أنواع عديدة أهمها:
- <Element - <E تستخدم كثيرا في مكتبات الجافا الافتراضية
- <Type - <T مقاربة للنوع الأول وأكثر الأنواع استخداما من قبل المطورين
- <Key & Value - <K, V للأنواع المتعددة (مفتاح وقيمة)
- ...
مثال على استخدام Generic الأنواع المتعددة:
public interface Pair<K, V> {
public K getKey();
public V getValue();
}
public class OrderedPair<K, V> implements Pair<K, V> {
private K key;
private V value;
public OrderedPair(K key, V value) {
this.key = key;
this.value = value;
}
public K getKey() { return key; }
public V getValue() { return value; }
}
ولإنشاء اوبجكت من الPair class:
Pair<String, Integer> p1 = new OrderedPair<String, Integer>("Even", 8);
Pair<String, String> p2 = new OrderedPair<String, String>("hello", "world");
يمكن الإستغناء عن تحديد انواع العناصر عند استدعاء الConstructor والاكتفاء بتحديدها عند التعريف، حيث يمكن للCompiler ان يربطهما.
OrderedPair<String, Integer> p1 = new OrderedPair<>("Even", 8);
OrderedPair<String, String> p2 = new OrderedPair<>("hello", "world");
المراجع
Oracle : The Java™ Tutorials: Generics (Updated)s
ntu : Java Programming Tutorial: Generics
التعليقات (0)
عرض المزيد.. جديد مقالاتي
لايوجد لديك حساب في عالم البرمجة؟
تحب تنضم لعالم البرمجة؟ وتنشئ عالمك الخاص، تنشر المقالات، الدورات، تشارك المبرمجين وتساعد الآخرين، اشترك الآن بخطوات يسيرة !