الدوال العامة (Generic Methods)
جزء من قسم البرمجة كائنية التوجه في رحلة Java على Coddy. الدرس 55 من 87.
بينما تجعل الفئات generic بأكملها تعمل مع أنواع مختلفة، قد تحتاج أحيانًا إلى أن تكون method واحدة فقط generic. تُعلن generic method عن معامل نوع خاص بها، مستقل عن أي معممات على مستوى class.
يظهر مُعامل النوع قبل نوع الإرجاع في توقيع الطريقة:
public class Utility {
public static <T> void printArray(T[] array) {
for (T element : array) {
System.out.println(element);
}
}
}
String[] names = {"Alice", "Bob"};
Integer[] numbers = {1, 2, 3};
Utility.printArray(names); // يعمل مع String[]
Utility.printArray(numbers); // يعمل مع Integer[]لاحظ <T> الموضوع بين المعدِّلات ونوع الإرجاع. يعلن هذا عن T كمعامل نوع لهذه الطريقة المحددة. يستنتج المصرّف النوع الفعلي من الوسائط التي تمرّرها.
يمكن للطرق generic أيضًا إرجاع النوع generic:
public static <T> T getFirst(T[] array) {
if (array.length > 0) {
return array[0];
}
return null;
}
String first = getFirst(new String[]{"a", "b"}); // يُرجع "a"يمكنك استخدام معلمات نوع متعددة عند الحاجة:
public static <K, V> void printPair(K key, V value) {
System.out.println(key + ": " + value);
}
printPair("Age", 25); // String و Integer
printPair(1, "First"); // Integer و Stringتكون الأساليب generic مفيدة بشكل خاص في فئات الأدوات حيث تحتاج إلى عمليات مرنة وقابلة لإعادة الاستخدام من دون إنشاء فئة generic.
التحدي
سهللنَبْنِ مجموعة أدوات مساعدة تُبرز مرونة الأساليب العامة. ستنشئ فئة تحتوي على أساليب قابلة لإعادة الاستخدام تعمل مع أي نوع، موضحًا كيف يمكن للأساليب العامة أن توجد بشكل مستقل عن الفئات العامة.
ستنظم التعليمات البرمجية عبر ملفين:
ArrayUtils.java: أنشئ فئة أدوات مساعدة تحتوي على أساليب عامة للعمل مع المصفوفات. يجب أن تحتوي فئتك على ثلاثة أساليب عامة static:getLast- أسلوب عام يأخذ مصفوفة من النوعTويُرجع العنصر الأخير. إذا كانت المصفوفة فارغة، فأرجِعnull.swap- أسلوب عام يأخذ مصفوفة من النوعTوموضعي integer، ثم يبدّل العناصر في هذين الموضعين. لا يُرجع هذا الأسلوب أي شيء.printWithLabel- أسلوب عام بمعلمَي نوعKوV. يأخذ label من النوعKوقيمة من النوعV، ثم يطبعهما بالتنسيق:[label]: [value]Main.java: شغّل أساليبك العامة! ستتلقى أربعة مدخلات: كلمتين (Strings) ورقمين (integers).أولًا، أنشئ مصفوفة
String[]containing الكلمتين معًا. استخدمgetLastللحصول على العنصر الأخير واطبع:Last word: [result]بعد ذلك، أنشئ مصفوفة
Integer[]containing الرقمين معًا. استدعِswapلتبديل العنصرين عند الموضعين 0 و1، ثم اطبع:After swap: [first], [second]أخيرًا، اعرض الأسلوب العام ذي المعلمَين باستدعاء
printWithLabelمرتين:- مرة باستخدام الكلمة الأولى باعتبارها label والرقم الأول باعتباره القيمة
- ومرة باستخدام الرقم الأول باعتباره label والكلمة الثانية باعتبارها القيمة
ستتلقى أربعة مدخلات بالترتيب: الكلمة الأولى، الكلمة الثانية، الرقم الأول، الرقم الثاني.
لاحظ كيف يعلن كل أسلوب عن معلم (معلمات) النوع الخاص به باستخدام <T> أو <K, V> قبل نوع الإرجاع. يستنتج المصرّف الأنواع الفعلية من الوسائط التي تمررها: لا حاجة إلى تحديدها صراحةً عند استدعاء الأساليب!
جرّب بنفسك
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// قراءة المدخلات
String firstWord = scanner.nextLine();
String secondWord = scanner.nextLine();
int firstNumber = scanner.nextInt();
int secondNumber = scanner.nextInt();
// TODO: إنشاء مصفوفة String[] تحتوي على كلا الكلمتين
// TODO: استخدام ArrayUtils.getLast للحصول على العنصر الأخير
// طباعة: "Last word: [result]"
// TODO: إنشاء مصفوفة Integer[] تحتوي على كلا الرقمين
// TODO: استدعاء ArrayUtils.swap للتبديل بين العناصر في الفهرسين 0 و 1
// طباعة: "After swap: [first], [second]"
// TODO: استدعاء ArrayUtils.printWithLabel باستخدام firstWord كـ label و firstNumber كـ value
// TODO: استدعاء ArrayUtils.printWithLabel باستخدام firstNumber كـ label و secondWord كـ value
}
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس البرمجة كائنية التوجه
1أساسيات الـ OOP
الملفات الخارجيةمقدمة في الـ OOPالفئات (Classes) مقابل الكائنات (Objects)الكلمة المفتاحية thisالدوال (Methods)الحقول (Attributes)دالة البناء (Constructor)تعدد أشكال دالة البناء (Constructor Overloading)مراجعة - آلة حاسبة بسيطة4الوراثة
الوراثة الأساسية (extends)الكلمة المفتاحية superإعادة تعريف الدوال (@Override)تسلسل المنشئات (Constructor Chaining)كلاس Objectالوراثة الأحادية ومتعددة المستوياتلماذا لا توجد وراثة متعددة للكلاساتمراجعة - هيكلية الموظفين7الدوال الخاصة وفئة Object
دالة toString()equals() و hashCode()دالة clone()compareTo() و Comparableواجهة Comparatorمراجعة - الترتيب المخصص2محددات الوصول والتغليف
نظرة عامة على مستويات الوصولدوال Getter و Setterإخفاء البياناتالكلمة المفتاحية finalمراجعة - مدير الحساب البنكي5تعدد الأشكال (Polymorphism)
أساسيات الـ Method Overloadingالـ Method Overriding (في وقت التشغيل)الـ Upcasting والـ Downcastingمعامل الـ instanceofالفئات والدوال المجردة (Abstract)مراجعة - حاسبة الأشكال8مفاهيم OOP المتقدمة
الـ Composition مقابل الـ Inheritanceالـ Aggregation مقابل الـ Compositionالفئات الداخلية والمتداخلة والمجهولة (Inner, Nested & Anonymous)الـ Enums ودوالهاالـ Records (Java 16+)الـ Sealed Classes (Java 17+)11أنماط التصميم - الجزء الأول
مقدمة في أنماط التصميمنمط Singletonنمط Factoryنمط Builderنمط Observerنمط Strategy3خصائص الفئة والعضو الساكن
المتغيرات الخاصة بالكائن مقابل المتغيرات الساكنةالدوال الساكنةالكتل البرمجية الساكنةالثوابت (static final)ملخص - العداد والأدوات المساعدة6الواجهات (Interfaces) والأصناف المجردة (Abstract Classes)
مقدمة في الواجهات (Interfaces)تنفيذ الواجهات (Interfaces)تنفيذ واجهات متعددةالـ Default و Static في الواجهاتالأصناف المجردة مقابل الواجهاتالواجهات الوظيفية (Functional Interfaces)مراجعة - نظام الدفع9الأنواع العامة (Generics)
مقدمة في الأنواع العامةالأصناف العامة (Generic Classes)الدوال العامة (Generic Methods)معاملات الأنواع المقيدةالرموز البديلة (?, extends, super)مراجعة - الحاويات العامة12أنماط التصميم - الجزء الثاني
نمط الأمرنمط المحولنمط المزيننمط طريقة القالبنمط الحالةنمط التركيبنمط المكررتدرّب بنفسك: مترجم Java عبر الإنترنت