JavaRush /Java blogi /Random-UZ /Java-da taqqoslash

Java-da taqqoslash

Guruhda nashr etilgan
Salom! Bugun biz ob'ektlarni taqqoslash haqida gaplashamiz. Hmm... Lekin biz bu haqda bir necha marta gaplashganga o'xshaymiz? :/ Biz “ ==” operatori qanday ishlashini, shuningdek equals()va usullarini bilamiz hashCode(). Taqqoslash aslida bu haqda emas. Ilgari biz ko'proq "ob'ektlarni tenglik uchun sinovdan o'tkazish" ni nazarda tutgan edik. Java-da solishtiruvchi - 1Ammo ob'ektlarni bir-biri bilan taqqoslash butunlay boshqacha maqsadlarga ega bo'lishi mumkin! Eng aniq biri - saralash. O'ylaymanki, agar sizga raqamlar yoki satrlar ro'yxatini tartiblash buyurilgan bo'lsa ArrayList<>, uni muammosiz hal qilishingiz mumkin:
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);
   }
}
Konsol chiqishi:

[Даша, Маша, Саша]
Agar siz sinf Collectionsva uning usulini eslab qolsangiz juda yaxshi sort(). Raqamlar bilan bog'liq muammolar ham bo'lmaydi, deb o'ylayman. Mana sizga qiyinroq vazifa:
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);
   }
}
Bu juda oddiy: sinf Carva uning 3 ta ob'ekti. Ro'yxatdagi mashinalarni saralash uchun mehribon bo'ling! Ehtimol siz: "Ularni qanday saralash kerak?" Deb so'rarsiz. Nomi, ishlab chiqarilgan yili, maksimal tezligi bo'yicha? Ajoyib savol. Biz hozircha sinf ob'ektlarini qanday saralashni bilmaymiz Car. Va, tabiiyki, Java ham buni bilmaydi! Collections.sort()Ob'ektlar ro'yxatini metodga o'tkazishga harakat qilganimizda Car, biz xatoga duch kelamiz:
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);
   }
}
Va haqiqatan ham, til siz yozgan ob'ektlarni qanday saralashni aniq biladi? Bu sizning dasturingiz maqsadlariga bog'liq. Biz qandaydir tarzda Java-ni ushbu ob'ektlarni taqqoslashni o'rgatishimiz kerak. Va bizga kerak bo'lgan usulni solishtiring. Shu maqsadda Java-da maxsus vosita mavjud - interfeys Comparable. Ingliz tilida bu "taqqoslash mumkin" deb tarjima qilingan. CarBizning ob'ektlarimizni bir-biri bilan taqqoslash va qandaydir tarzda tartiblash uchun sinf ushbu interfeysni amalga oshirishi va uning yagona usulini amalga oshirishi kerak: 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()

}
Diqqat qilish:biz interfeysni ko'rsatdik Comparable<Car>, nafaqat Comparable. Bu terilgan interfeys, ya'ni u bog'langan maxsus sinfning spetsifikatsiyasini talab qiladi. Asos sifatida, <Car>siz uni interfeysdan olib tashlashingiz mumkin, lekin keyin u ob'ektlarni sukut bo'yicha taqqoslaydi Object. compareTo(Car o)Bizning sinfimizdagi usul o'rniga bizda quyidagilar bo'ladi:
@Override
   public int compareTo(Object o) {
       return 0;
   }
Albatta, biz bilan ishlash ancha oson Car. Usul ichida compareTo()biz mashinalarni taqqoslash mantiqini amalga oshiramiz. Aytaylik, ularni ishlab chiqarilgan yili bo'yicha saralashimiz kerak. Ehtimol, bu usul emas, balki compareTo()qiymatni qaytarayotganini payqadingiz . Bu sizni ajablantirishiga yo'l qo'ymang. Gap shundaki, ikkita ob'ektni taqqoslash bizga uchta mumkin bo'lgan variantni beradi: intboolean
  • а < b
  • a > b
  • a == b.
U booleanfaqat ikkita qiymatga ega - haqiqiy va noto'g'ri, bu ob'ektlarni solishtirish uchun noqulay. Hammasi intancha sodda. Qaytish qiymati > 0bo'lsa, u holda a > b. Agar natija compareTo < 0bo'lsa, unda а < b. Xo'sh, agar natija bo'lsa == 0, ikkita ob'ekt teng bo'ladi: a == b. Bizning sinfimizga avtomobillarni ishlab chiqarilgan yili bo'yicha saralashni o'rgatish nokni otish kabi oson:
@Override
public int compareTo(Car o) {
   return this.getManufactureYear() - o.getManufactureYear();
}
Bu yerda nima bo'lyapti? Biz bitta avtomobil ob'ektini ( this), ushbu avtomobilning ishlab chiqarilgan yilini olamiz va undan boshqa avtomobilning ishlab chiqarilgan yilini ayirib olamiz (biz ob'ektni solishtiradigan). Agar birinchi avtomobilning ishlab chiqarilgan yili kattaroq bo'lsa, usul qaytadi int > 0. Bu degani, mashina this >- bu mashina о. Aksincha, ikkinchi avtomobilning ishlab chiqarilgan yili ( о) kattaroq bo'lsa, u holda usul salbiy raqamni qaytaradi va shuning uchun о > this. Xo'sh, agar ular teng bo'lsa, usul qaytib keladi 0. Bunday oddiy mexanizm ob'ektlar to'plamini saralash uchun allaqachon etarli Car! Boshqa hech narsa qilishingiz shart emas. Mana marhamat:
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);
   }
}
Konsol chiqishi:

[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}]
Mashinalar bo'lishi kerak bo'lgan tarzda tartiblangan! :) Java-da taqqoslash - 2Qanday hollarda foydalanish kerak Comparable? Amalga oshirilgan taqqoslash usuli Comparable"tabiiy tartiblash" deb ataladi. Buning sababi shundaki, usulda compareTo()siz dasturingizda ushbu sinf ob'ektlari uchun ishlatiladigan eng keng tarqalgan taqqoslash usulini tavsiflaysiz. Tabiiy tartib Java-da allaqachon mavjud. Masalan, Java satrlar ko'pincha alifbo tartibida va raqamlar ko'pincha ortib borayotgan qiymat bo'yicha tartiblanganligini biladi. Shuning uchun, agar siz raqamlar yoki satrlar ro'yxatidagi usulni chaqirsangiz sort(), ular tartiblanadi. Comparable<Car>Agar bizning dasturimizda avtomobillar ko'p hollarda ishlab chiqarilgan yili bo'yicha taqqoslanadigan va saralangan bo'lsa, u holda interfeys va usul yordamida ular uchun tabiiy turni aniqlashga arziydi compareTo(). Ammo bu biz uchun etarli bo'lmasa-chi? Tasavvur qilaylik, bizning dasturimiz unchalik oddiy emas. Ko'pgina hollarda, avtomashinalarning tabiiy saralanishi (biz uni ishlab chiqarilgan yili bo'yicha o'rnatamiz) bizga mos keladi. Ammo ba'zida mijozlarimiz orasida tez haydashni yaxshi ko'radiganlar bor. Agar biz ularni tanlash uchun mashinalar katalogini tayyorlayotgan bo'lsak, ular maksimal tezlikda buyurtma berishlari kerak. Java-da taqqoslash - 3Misol uchun, biz 15% hollarda bunday saralashga muhtojmiz. CarBu ishlab chiqarilgan yili o'rniga tezlik bo'yicha tabiiy saralashni o'rnatish uchun etarli emas . Ammo biz mijozlarning 15 foizini e'tiborsiz qoldira olmaymiz. Biz nima qilamiz? Bu erda bizning yordamimizga yana bir interfeys keladi - Comparator. Xuddi Comparableterilgan kabi. Nima farqi bor? Comparableob'ektlarimizni "taqqoslash mumkin" qiladi va ular uchun ko'p hollarda ishlatiladigan eng tabiiy tartibni yaratadi. Comparator- bu alohida "taqqoslovchi" sinf (tarjima biroz noqulay, ammo tushunarli). CarAgar biz muayyan saralashni amalga oshirishimiz kerak bo'lsa, biz sinfga kirib , mantiqni o'zgartirishimiz shart emas compareTo(). Buning o'rniga biz dasturimizda alohida taqqoslash sinfini yaratib, unga kerakli saralashni o'rgatishimiz mumkin!
import java.util.Comparator;

public class MaxSpeedCarComparator implements Comparator<Car> {

   @Override
   public int compare(Car o1, Car o2) {
       return o1.getMaxSpeed() - o2.getMaxSpeed();
   }
}
Ko'rib turganingizdek, bizniki Comparatorjuda oddiy. Faqat bitta usul mavjud compare()- bu interfeys usuli Comparator, uni amalga oshirish kerak. Kirish sifatida ikkita ob'ektni oladi Carva ularning maksimal tezligini odatdagi usulda (ayirish orqali) solishtiradi. Kabi compareTo(), raqamni qaytaradi int, taqqoslash printsipi bir xil. Bundan qanday foydalanishimiz mumkin? Juda oddiy:
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);
   }
}
Konsol chiqishi:

[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()Biz shunchaki taqqoslash ob'ektini yaratamiz va uni saralanadigan ro'yxat bilan birga usulga o'tkazamiz . Kirish sifatida solishtirgichni olgandan so'ng, usul sinf sort()usulida belgilangan tabiiy saralashni ishlatmaydi . Buning o'rniga, unga o'tkazilgan taqqoslagichdan saralash algoritmini qo'llaydi. Bu bizga qanday afzalliklarni beradi? Birinchidan, yozilgan kod bilan muvofiqligi. Biz hozirgisini saqlab qolgan holda, ko'p hollarda qo'llaniladigan yangi, o'ziga xos saralash usulini yaratdik. Biz sinfga umuman tegmadik . U xuddi shunday qoldi: 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()

}
Ikkinchidan, moslashuvchanlik. Biz xohlagancha ko'p navlarni qo'shishimiz mumkin. Aytaylik, mashinalarni rangi, tezligi, vazni yoki Botmen filmlarida mashina necha marta ishlatilganiga qarab tartiblang. Faqatgina qo'shimcha yaratish kifoya Comparator. Ana xolos! Bugun siz ishda haqiqiy loyihalarda tez-tez foydalanadigan ikkita juda muhim mexanizmni o'rgandingiz. Ammo, siz bilganingizdek, amaliyotsiz nazariya hech narsa emas. Shuning uchun, bilimlaringizni mustahkamlash va bir nechta muammolarni hal qilish vaqti keldi! :)
Izohlar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION