CodeGym /وبلاگ جاوا /Random-FA /کلاس مقایسه جاوا
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);
   }
}
و در واقع، چگونه زبان می داند که چگونه اشیاء کلاس هایی را که شما نوشته اید مرتب کند؟ این بستگی به این دارد که برنامه شما باید چه کاری انجام دهد. ما باید به نحوی به جاوا یاد بدهیم که این اشیاء را با هم مقایسه کند. و آنها را همانطور که می خواهیم مقایسه کنیم. جاوا مکانیزم خاصی برای این کار دارد: 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()متد a را برمی گرداند intنه a boolean. اجازه ندهید این شما را غافلگیر کند. وقتی دو شی را با هم مقایسه می کنیم، 3 احتمال وجود دارد:
  • а < b
  • a > b
  • a == b.
booleanفقط 2 مقدار دارد: true و false که برای مقایسه اشیا به خوبی کار نمی کند. با int، همه چیز بسیار ساده تر است. اگر مقدار بازگشتی باشد > 0، پس a > b. اگر نتیجه از compareTo, < 0پس a < b. و اگر نتیجه برابر باشد == 0، دو شی مساوی هستند: a == 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()متد رایج ترین یا طبیعی ترین روش مقایسه اشیاء این کلاس را تعریف می کنید. جاوا از قبل یک نظم طبیعی دارد. به عنوان مثال، جاوا می داند که رشته ها اغلب بر اساس حروف الفبا مرتب می شوند و اعداد با افزایش مقدار عددی مرتب می شوند. 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()استفاده نمی کند . در عوض، الگوریتم مرتب‌سازی تعریف شده توسط مقایسه‌کننده را اعمال می‌کند. مزایای انجام این کار چیست؟ اول، سازگاری با کد موجود. ما یک روش مرتب‌سازی جدید و ویژه ایجاد کردیم، در حالی که روش موجود را حفظ می‌کنیم که بیشتر اوقات استفاده می‌شود. ما اصلا به کلاس دست نزدیم . این یک بود و بنابراین باقی می ماند: CarcompareTo()CarComparable
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