JavaRush /وبلاگ جاوا /Random-FA /مقایسه کننده در جاوا

مقایسه کننده در جاوا

در گروه منتشر شد
سلام! امروز در مورد مقایسه اشیاء صحبت خواهیم کرد. هوم... اما به نظر می رسد قبلاً بیش از یک بار در مورد این موضوع صحبت کرده ایم؟ :/ ما می دانیم که ==عملگر " " چگونه کار می کند و همچنین روش های 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);
   }
}
و واقعاً، چگونه زبان دقیقاً می داند که چگونه اشیایی را که می نویسید مرتب کند؟ این بستگی به اهداف برنامه شما دارد. ما باید به نحوی به جاوا یاد بدهیم که این اشیاء را با هم مقایسه کند. و روشی را که ما به آن نیاز داریم مقایسه کنیم. برای این منظور جاوا یک ابزار ویژه دارد - رابط 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. اجازه ندهید این شما را غافلگیر کند. واقعیت این است که مقایسه دو شی 3 گزینه ممکن را به ما می دهد:
  • а < b
  • a > b
  • a == b.
این booleanفقط 2 مقدار دارد - true و false که برای مقایسه اشیا ناخوشایند است. همه چیز بسیار ساده تر است 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()رایج ترین روش مقایسه ای را که برای اشیاء این کلاس در برنامه شما استفاده می شود، توصیف می کنید. نظم طبیعی در حال حاضر در جاوا وجود دارد. به عنوان مثال، جاوا می داند که رشته ها اغلب بر اساس حروف الفبا مرتب می شوند و اعداد اغلب بر اساس مقدار صعودی مرتب می شوند. بنابراین، اگر متد را در لیستی از اعداد یا رشته ها فراخوانی کنید 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()CarCarComparable
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