CodeGym /مدونة جافا /Random-AR /فئة المقارنة في جافا
John Squirrels
مستوى
San Francisco

فئة المقارنة في جافا

نشرت في المجموعة
أهلاً! اليوم سنتحدث عن مقارنة الأشياء. فئة المقارنة في جافا - 1 حسنًا... لكن ألم نتحدث بالفعل عن هذا الموضوع أكثر من مرة؟ :/ نحن نعرف كيفية ==عمل المشغل، وكذلك equals()الأساليب hashCode(). المقارنة مختلفة قليلا. في السابق، كنا نعني على الأرجح "التحقق من الأشياء من أجل المساواة". لكن أسباب مقارنة الأشياء ببعضها البعض يمكن أن تكون مختلفة تمامًا! الأكثر وضوحا من هذه هو الفرز. أعتقد أنه إذا طُلب منك فرز عدد ArrayList<>من الأرقام أو السلاسل، فستتمكن من التعامل مع هذا دون أي مشاكل:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Main {

   public static void main(String[] args) {

       String name1 = "Masha";
       String name2 = "Sasha";
       String name3 = "Dasha";

       List<String> names = new ArrayList<>();
       names.add(name1);
       names.add(name2);
       names.add(name3);

       Collections.sort(names);
       System.out.println(names);
   }
}
إخراج وحدة التحكم:

[Dasha, Masha, Sasha]
إذا تذكرت الفصل Collectionsوطريقته sort()، أحسنت! أعتقد أنك لن تواجه مشكلة مع الأرقام أيضًا. إليك مهمة أكثر تحديًا بالنسبة لك:
public class Car {

   private int manufactureYear;
   private String model;
   private int maxSpeed;

   public Car(int manufactureYear, String model, int maxSpeed) {
       this.manufactureYear = manufactureYear;
       this.model = model;
       this.maxSpeed = maxSpeed;
   }

   // ...getters, setters, toString()

}

import java.util.ArrayList;
import java.util.List;

public class Main {

   public static void main(String[] args) {

       List<Car> cars = new ArrayList<>();

       Car ferrari = new Car(1990, "Ferrari 360 Spider", 310);
       Car lambo = new Car(2012, "Lamborghini Gallardo", 290);
       Car bugatti = new Car(2010, "Bugatti Veyron", 350);

       cars.add(ferrari);
       cars.add(bugatti);
       cars.add(lambo);
   }
}
المهمة في الواقع بسيطة. لدينا Carفئة و3 كائنات سيارة. هل تتفضل بفرز السيارات في القائمة؟ من المحتمل أن تسأل: "كيف ينبغي فرزها؟" بالاسم؟ حسب سنة الصنع؟ بالسرعة القصوى؟ سؤال ممتاز. في الوقت الحالي، لا نعرف كيفية فرز الأشياء Car. ومن الطبيعي أن جافا لا تعرف ذلك أيضًا! عندما نحاول تمرير قائمة Carالكائنات إلى Collections.sort()الطريقة، نحصل على خطأ:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Main {

   public static void main(String[] args) {

       List<Car> cars = new ArrayList<>();

       Car ferrari = new Car(1990, "Ferrari 360 Spider", 310);
       Car lambo = new Car(20012, "Lamborghini Gallardo", 290);
       Car bugatti = new Car(2010, "Bugatti Veyron", 350);

       cars.add(ferrari);
       cars.add(bugatti);
       cars.add(lambo);

       // Compilation error!
       Collections.sort(cars);
   }
}
وبالفعل، كيف يمكن للغة أن تعرف كيفية فرز كائنات الفئات التي كتبتها؟ هذا يعتمد على ما يحتاج برنامجك للقيام به. يجب علينا أن نعلم جافا بطريقة ما كيفية مقارنة هذه الكائنات. ومقارنتها بالطريقة التي نريدها. لدى Java آلية خاصة لهذا: Comparableالواجهة. من أجل مقارنة كائناتنا وفرزها بطريقة أو بأخرى Car، يجب على الفصل تنفيذ هذه الواجهة، والتي تتكون من طريقة واحدة: compareTo():
public class Car implements Comparable<Car> {

   private int manufactureYear;
   private String model;
   private int maxSpeed;

   public Car(int manufactureYear, String model, int maxSpeed) {
       this.manufactureYear = manufactureYear;
       this.model = model;
       this.maxSpeed = maxSpeed;
   }

   @Override
   public int compareTo(Car o) {
       return 0;
   }

   // ...getters, setters, toString()

}
يرجى الملاحظةأننا حددنا الواجهة Comparable<Car>، وليس فقط Comparable. هذه واجهة ذات معلمات، أي أنه يجب علينا تحديد الفئة المرتبطة المحددة. من حيث المبدأ، يمكنك الإزالة <Car>من الواجهة، ولكن بعد ذلك ستعتمد المقارنة على Objectالكائنات بشكل افتراضي. بدلاً من compareTo(Car o)الطريقة، سيكون لفصلنا:
@Override
   public int compareTo(Object o) {
       return 0;
   }
وبطبيعة الحال، فإنه من الأسهل بالنسبة لنا أن نعمل مع Car. داخل compareTo()الطريقة، نقوم بتنفيذ منطقنا لمقارنة السيارات. لنفترض أننا بحاجة إلى فرزها حسب سنة الصنع. ربما لاحظت أن compareTo()الطريقة تُرجع ملفًا intوليس ملفًا boolean. لا تدع هذا يفاجئك. عندما نقارن بين شيئين، هناك ثلاثة احتمالات:
  • а < b
  • a > b
  • a == b.
booleanيحتوي على قيمتين فقط: صحيح وخطأ، وهو ما لا يعمل بشكل جيد لمقارنة الكائنات. مع int، كل شيء أبسط من ذلك بكثير. > 0إذا كانت قيمة الإرجاع هي a > b. إذا كانت النتيجة compareToهي . وإذا كانت النتيجة ، فإن شيئين متساويان: . إن تعليم فصلنا كيفية فرز السيارات حسب سنة الصنع هو أمر سهل للغاية: < 0a < b== 0a == b
@Override
public int compareTo(Car o) {
   return this.getManufactureYear() - o.getManufactureYear();
}
ولكن ماذا يحدث هنا؟ نأخذ قطعة سيارة واحدة ( this)، ونحصل على سنة تصنيع هذه السيارة، ونطرح منها سنة تصنيع سيارة أخرى (السيارة التي تتم مقارنة السلعة بها). إذا كانت سنة تصنيع السيارة الأولى أكبر، فسوف تقوم الطريقة بإرجاع int > 0. وهذا يعني أن this car >السيارة o. وعلى العكس من ذلك، إذا كانت سنة تصنيع السيارة الثانية ( о) أكبر، فإن الطريقة ستعيد رقمًا سالبًا، مما يعني ذلك o > this. أخيرًا، إذا كانا متساويين، فستعود الطريقة 0. هذه الآلية البسيطة كافية بالفعل لفرز مجموعات من Carالكائنات! ليس عليك أن تفعل أي شيء آخر. تحقق من ذلك:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Main {

   public static void main(String[] args) {

       List<Car> cars = new ArrayList<>();

       Car ferrari = new Car(1990, "Ferrari 360 Spider", 310);
       Car lambo = new Car(2012, "Lamborghini Gallardo", 290);
       Car bugatti = new Car(2010, "Bugatti Veyron", 350);

       cars.add(ferrari);
       cars.add(bugatti);
       cars.add(lambo);

       // There was previously an error here
       Collections.sort(cars);
       System.out.println(cars);
   }
}
إخراج وحدة التحكم:

[Car{manufactureYear=1990, model='Ferrari 360 Spider', maxSpeed=310}, 
Car{manufactureYear=2010, model='Bugatti Veyron', maxSpeed=350}, 
Car{manufactureYear=2012, model='Lamborghini Gallardo', maxSpeed=290}]
يتم فرز السيارات كما نريد! :) فئة المقارنة في جافا - 2متى يجب أن أستخدم Comparable؟ طريقة المقارنة المطبقة Comparableتسمى الترتيب الطبيعي. وذلك لأنه في هذه compareTo()الطريقة تحدد الطريقة الأكثر شيوعًا أو الطبيعية لمقارنة كائنات هذه الفئة. تتمتع Java بالفعل بترتيب طبيعي. على سبيل المثال، تعرف Java أن السلاسل يتم فرزها في أغلب الأحيان أبجديًا، ويتم فرز الأرقام عن طريق زيادة القيمة الرقمية. لذلك، إذا قمت باستدعاء sort()الأسلوب على قائمة أرقام أو سلاسل، فسيتم فرزها. إذا كان برنامجنا يقوم عادة بمقارنة وفرز السيارات حسب سنة الصنع، فيجب علينا تحديد الفرز الطبيعي للسيارات باستخدام الواجهة Comparable<Car>والطريقة compareTo(). ولكن ماذا لو كان هذا لا يكفي بالنسبة لنا؟ دعونا نتخيل أن برنامجنا ليس بهذه البساطة. في معظم الحالات، فإن الفرز الطبيعي للسيارات (الذي حددناه ليتم إجراؤه حسب سنة الصنع) يناسبنا. لكن في بعض الأحيان يكون عملاؤنا من عشاق القيادة السريعة. إذا كنا نجهز كتالوجًا للسيارات ليطلعوا عليه، فيجب فرز السيارات حسب السرعة القصوى. فئة المقارنة في جافا - 3على سبيل المثال، لنفترض أننا بحاجة إلى الفرز بهذه الطريقة بنسبة 15% من الوقت. من الواضح أن هذا لا يكفي بالنسبة لنا لضبط Carالفرز الطبيعي للفصل على أساس السرعة بدلاً من سنة الصنع. لكن لا يمكننا تجاهل 15% من عملائنا. إذن ماذا نفعل؟ واجهة أخرى تأتي لمساعدتنا هنا: Comparator. تمامًا مثل Comparable، إنها واجهة ذات معلمات. ماهو الفرق؟ Comparableيجعل كائناتنا "قابلة للمقارنة" ويحدد ترتيب الفرز الأكثر طبيعية، أي ترتيب الفرز الذي سيتم استخدامه في معظم الحالات. Comparatorهي واجهة "مقارنة" منفصلة. إذا كنا بحاجة إلى تنفيذ نوع من ترتيب الفرز الخاص، فلن نحتاج إلى الدخول إلى الفصل Carوتغيير منطق compareTo(). بدلاً من ذلك، يمكننا إنشاء فئة منفصلة تقوم بتنفيذ Comparator وتعليمها كيفية إجراء الفرز الذي نحتاجه!
import java.util.Comparator;

public class MaxSpeedCarComparator implements Comparator<Car> {

   @Override
   public int compare(Car o1, Car o2) {
       return o1.getMaxSpeed() - o2.getMaxSpeed();
   }
}
كما ترون، لدينا Comparatorبسيطة جدا. نحتاج إلى تنفيذ طريقة واجهة واحدة فقط: compare(). يأخذ Carكائنين كمدخلات ويقارن سرعتهما القصوى بالطريقة المعتادة (عن طريق الطرح). مثل compareTo()، تقوم بإرجاع int، ومبدأ المقارنة هو نفسه. كيف نستخدم هذا؟ كل شيء واضح ومباشر:
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class Main {

   public static void main(String[] args) {

       List<Car> cars = new ArrayList<>();

       Car ferrari = new Car(1990, "Ferrari 360 Spider", 310);
       Car lambo = new Car(2012, "Lamborghini Gallardo", 290);
       Car bugatti = new Car(2010, "Bugatti Veyron", 350);

       cars.add(ferrari);
       cars.add(bugatti);
       cars.add(lambo);

       Comparator speedComparator = new MaxSpeedCarComparator();
       Collections.sort(cars, speedComparator);

       System.out.println(cars);
   }
}
إخراج وحدة التحكم:

[Car{manufactureYear=2012, model='Lamborghini Gallardo', maxSpeed=290}, 
Car{manufactureYear=1990, model='Ferrari 360 Spider', maxSpeed=310}, 
Car{manufactureYear=2010, model='Bugatti Veyron', maxSpeed=350}]
نقوم ببساطة بإنشاء كائن مقارنة وتمريره إلى Collections.sort()الطريقة مع القائمة المراد فرزها. عندما sort()تتلقى الطريقة مقارنة، فإنها لا تستخدم الفرز الطبيعي المحدد في طريقة Carالفئة compareTo(). وبدلاً من ذلك، فإنه يطبق خوارزمية الفرز المحددة بواسطة المقارنة التي تم تمريرها إليها. ما هي مزايا القيام بذلك؟ أولاً، التوافق مع التعليمات البرمجية الموجودة. لقد أنشأنا طريقة فرز جديدة خاصة، مع الاحتفاظ بالطريقة الحالية التي سيتم استخدامها في معظم الأوقات. لم نلمس Carالفصل على الإطلاق. لقد كان Comparable، وهكذا يبقى:
public class Car implements Comparable<Car> {

   private int manufactureYear;
   private String model;
   private int maxSpeed;

   public Car(int manufactureYear, String model, int maxSpeed) {
       this.manufactureYear = manufactureYear;
       this.model = model;
       this.maxSpeed = maxSpeed;
   }

   @Override
   public int compareTo(Car o) {
       return this.getManufactureYear() - o.getManufactureYear();
   }

   // ...getters, setters, toString()

}
ثانيا، المرونة. يمكننا إضافة أي عدد نريده من خوارزميات الفرز. على سبيل المثال، يمكننا فرز السيارات حسب اللون، أو السرعة، أو الوزن، أو حسب عدد مرات استخدام السيارة في أفلام باتمان. كل ما يتعين علينا القيام به هو إنشاء ملف Comparator. هذا كل شيء! لقد قمت اليوم بدراسة آليتين مهمتين للغاية ستستخدمهما غالبًا في المشاريع الحقيقية في العمل. ولكن، كما تعلمون، النظرية دون ممارسة لا شيء. حان الوقت الآن لتعزيز معرفتك وإكمال بعض المهام!
تعليقات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION