JavaRush /مدونة جافا /Random-AR /المقارنة في جافا

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

نشرت في المجموعة
مرحبًا! اليوم سنتحدث عن مقارنة الأشياء. حسنًا... ولكن يبدو أننا تحدثنا بالفعل عن هذا أكثر من مرة؟ :/ نحن نعرف كيفية ==عمل عامل التشغيل " " وكذلك الأساليب equals()والطرق hashCode(). المقارنة ليست حقا حول ذلك. في السابق، كنا نعني أكثر مثل "اختبار الأشياء من أجل المساواة". المقارنة في جافا - 1لكن مقارنة الأشياء ببعضها البعض قد يكون لها أهداف مختلفة تمامًا! الأكثر وضوحا هو الفرز. أعتقد أنه إذا طُلب منك فرز قائمة من 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 = "Даша";

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

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

[Даша, Маша, Саша]
إنه لأمر رائع أن تتذكر الفصل 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;
   }

   //...геттеры, сеттеры, 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. ومن الطبيعي أن جافا لا تعرف هذا أيضًا! عندما نحاول تمرير Collections.sort()قائمة بالكائنات إلى إحدى العمليات 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(20012, "Lamborghini Gallardo", 290);
       Car bugatti = new Car(2010, "Bugatti Veyron", 350);

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

       //ошибка компилятора!
       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;
   }

   //...геттеры, сеттеры, 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 < 0إذن а < b. حسنًا، إذا كانت النتيجة == 0، فإن الشيئين متساويان: a == b. إن تعليم فصلنا كيفية فرز السيارات حسب سنة الصنع أمر سهل مثل قشر الكمثرى:
@Override
public int compareTo(Car o) {
   return this.getManufactureYear() - o.getManufactureYear();
}
ما الذي يحدث هنا؟ نأخذ قطعة سيارة واحدة ( this) سنة تصنيع هذه السيارة ونطرح منها سنة تصنيع سيارة أخرى (السيارة التي نقارن بها القطعة). وإذا كانت سنة صنع السيارة الأولى أكبر تعود الطريقة int > 0. مما يعني أن السيارة this >هي سيارة о. على العكس من ذلك، إذا كانت سنة تصنيع السيارة الثانية ( о) أكبر، فستُرجع الطريقة رقمًا سالبًا، وبالتالي о > 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);

       //тут раньше была ошибка
       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(). بدلًا من ذلك، يمكننا إنشاء فئة مقارنة منفصلة في برنامجنا وتعليمها كيفية الفرز الذي نحتاجه!
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()- وهي طريقة واجهة Comparatorيجب تنفيذها. يأخذ كائنين كمدخلات 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()لن تستخدم الطريقة الفرز الطبيعي المحدد في طريقة compareTo()الفصل Car. بدلاً من ذلك، سيتم تطبيق خوارزمية الفرز من المقارنة التي تم تمريرها إليها. ما هي المزايا التي يقدمها لنا هذا؟ أولاً، التوافق مع الكود المكتوب. لقد أنشأنا طريقة فرز جديدة ومحددة، مع الحفاظ على الطريقة الحالية، والتي سيتم استخدامها في معظم الحالات. لم نلمس الفصل على الإطلاق 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();
   }

   //...геттеры, сеттеры, toString()

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