compareTo() و Comparable
جزء من قسم Object Oriented Programming في رحلة Java على Coddy — الدرس 44 من 87.
تسمح واجهة Comparable للكائنات بتعريف ترتيبها الطبيعي. من خلال تنفيذ هذه الواجهة، يمكن فرز فئتك (class) تلقائيًا باستخدام طرق مثل Collections.sort() أو تخزينها في مجموعات مرتبة مثل TreeSet.
تتطلب الواجهة منك تنفيذ طريقة واحدة: compareTo(). تقوم هذه الطريقة بمقارنة الكائن الحالي بكائن آخر وتعيد عدداً صحيحاً يشير إلى ترتيبهما النسبي:
- قيمة سالبة: يأتي هذا الكائن قبل الآخر
- صفر: كلا الكائنين متساويان
- قيمة موجبة: يأتي هذا الكائن بعد الآخر
public class Person implements Comparable<Person> {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public int compareTo(Person other) {
return this.age - other.age; // الترتيب حسب العمر تصاعدياً
}
}بمجرد التنفيذ، يصبح الفرز بسيطاً:
List<Person> people = new ArrayList<>();
people.add(new Person("Alice", 30));
people.add(new Person("Bob", 25));
Collections.sort(people); // مرتبة الآن حسب العمر: Bob, Aliceلمقارنة السلاسل النصية أو غيرها من الحقول التي تدعم Comparable، يمكنك التفويض إلى طريقة compareTo() الخاصة بها بدلاً من استخدام الطرح: return this.name.compareTo(other.name);. هذا النهج أكثر أماناً ويتعامل مع الحالات الاستثنائية بشكل صحيح.
التحدي
سهللنقم ببناء نظام لتصنيف الأفلام يستخدم واجهة Comparable لفرز الأفلام حسب تقييماتها. ستقوم بإنشاء فئة Movie تعرف كيفية مقارنة نفسها بالأفلام الأخرى، مما يتيح الفرز التلقائي من الأعلى تقييماً إلى الأقل.
ستقوم بتنظيم الكود الخاص بك عبر ملفين:
Movie.java: قم بإنشاء فئة تمثل فيلماً يمكن مقارنته بالأفلام الأخرى. يحتوي الفيلم على ثلاثة حقول خاصة:title(String)، وdirector(String)، وrating(double، من 0.0 إلى 10.0). قم بتضمين منشئ (constructor) لتهيئة جميع الحقول وطرق جلب (getter methods) لكل منها.اجعل فئة Movie الخاصة بك تنفذ
Comparable<Movie>وقم بتجاوز طريقةcompareTo(). يجب فرز الأفلام حسب التقييم في ترتيب تنازلي (الأعلى تقييماً أولاً). عند مقارنة القيم من نوع double، استخدمDouble.compare()لإجراء مقارنة آمنة — تذكر عكس الترتيب للفرز التنازلي!قم بتجاوز
toString()لترجع:[title] by [director] - Rating: [rating]Main.java: ابعث الحياة في فئة Movie الخاصة بك عن طريق إنشاء قائمة من الأفلام وفرزها. ستتلقى مدخلات لثلاثة أفلام، كل منها في سطر منفصل بالتنسيق التالي:title,director,ratingقم بتحليل كل سطر لإنشاء كائنات Movie، وأضفها إلى
ArrayList، ثم استخدمCollections.sort()لفرز القائمة. بفضل تنفيذك لواجهةComparable، ستترتب الأفلام تلقائياً حسب التقييم!بعد الفرز، اطبع كل فيلم في سطر خاص به باستخدام تنسيق
toString(). يجب أن يظهر الفيلم الأعلى تقييماً أولاً.
ستتلقى ثلاثة أسطر من المدخلات، يحتوي كل منها على بيانات الفيلم بالتنسيق: title,director,rating
على سبيل المثال، قد يبدو سطر الإدخال كما يلي: Inception,Christopher Nolan,8.8
تذكر استيراد java.util.ArrayList و java.util.Collections و java.util.Scanner في ملف Main الخاص بك. لاحظ كيف يتيح لك تنفيذ Comparable فرز كائناتك المخصصة باستدعاء طريقة واحدة فقط — دون الحاجة إلى مقارن (comparator) إضافي!
ورقة مرجعية
تسمح واجهة Comparable للكائنات بتعريف ترتيبها الطبيعي للفرز التلقائي.
قم بتنفيذ طريقة compareTo() التي تُرجع:
- قيمة سالبة: هذا الكائن يأتي قبل الآخر
- صفر: كلا الكائنين متساويان
- قيمة موجبة: هذا الكائن يأتي بعد الآخر
public class Person implements Comparable<Person> {
private int age;
@Override
public int compareTo(Person other) {
return this.age - other.age; // فرز حسب العمر تصاعدياً
}
}قم بفرز الكائنات باستخدام Collections.sort():
List<Person> people = new ArrayList<>();
people.add(new Person("Alice", 30));
people.add(new Person("Bob", 25));
Collections.sort(people); // تم الفرز حسب العمرلمقارنة السلاسل النصية، قم بالتفويض إلى طريقة compareTo() الخاصة بها:
return this.name.compareTo(other.name);لمقارنة القيم من نوع double بأمان، استخدم Double.compare():
return Double.compare(this.rating, other.rating); // تصاعدي
return Double.compare(other.rating, this.rating); // تنازليجرّب بنفسك
import java.util.ArrayList;
import java.util.Collections;
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// قراءة ثلاثة أسطر من بيانات الأفلام
String line1 = scanner.nextLine();
String line2 = scanner.nextLine();
String line3 = scanner.nextLine();
// TODO: إنشاء ArrayList لتخزين كائنات Movie
// TODO: تحليل كل سطر (التنسيق: title,director,rating)
// Hint: استخدم split(",") لفصل الأجزاء
// Hint: استخدم Double.parseDouble() من أجل rating
// TODO: إنشاء كائنات Movie وإضافتها إلى القائمة
// TODO: فرز القائمة باستخدام Collections.sort()
// TODO: طباعة كل فيلم (واحد في كل سطر)
}
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس Object Oriented Programming
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أنماط التصميم - الجزء الثاني
نمط الأمرنمط المحولنمط المزيننمط طريقة القالبنمط الحالةنمط التركيبنمط المكرر