CodeGym /Blog Java /Aleatoriu /Clasa Comparator Java
John Squirrels
Nivel
San Francisco

Clasa Comparator Java

Publicat în grup
Bună! Astăzi vom vorbi despre compararea obiectelor. Clasa Comparator Java - 1 Hmm... Dar nu am vorbit deja despre acest subiect de mai multe ori? :/ Știm cum ==funcționează operatorul, precum și metodele equals()și hashCode(). Comparația este puțin diferită. Anterior, cel mai probabil ne-am referit la „verificarea egalității obiectelor”. Dar motivele comparării obiectelor între ele pot fi complet diferite! Cea mai evidentă dintre acestea este sortarea. Cred că dacă vi s-ar spune să sortați ArrayList<>numere sau șiruri de caractere, ați putea face față fără probleme:

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);
   }
}
Ieșire din consolă:

[Dasha, Masha, Sasha]
Daca ti-ai amintit Collectionsclasa si sort()metoda ei, bravo! Cred că nici nu vei avea probleme cu numerele. Iată o sarcină mai provocatoare pentru tine:

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);
   }
}
Sarcina este de fapt simplă. Avem o Carclasă și 3 obiecte Car. Ați face bine să sortați mașinile din listă? Probabil vă veți întreba: „Cum ar trebui să fie sortate?” Dupa nume? După anul de fabricație? Cu viteza maxima? Excelenta intrebare. Momentan, nu știm cum să sortăm obiectele Car. Și, firesc, nici Java nu știe asta! Când încercăm să transmitem o listă de Carobiecte metodei Collections.sort(), obținem o eroare:

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);
   }
}
Și într-adevăr, cum ar ști limbajul să sorteze obiectele claselor pe care le-ai scris? Acest lucru depinde de ceea ce trebuie să facă programul dvs. Trebuie să învățăm cumva Java să compare aceste obiecte. Și să le comparăm așa cum ne dorim. Java are un mecanism special pentru asta: interfața Comparable. Pentru a compara și sorta cumva Carobiectele noastre, clasa trebuie să implementeze această interfață, care constă dintr-o singură metodă: 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()

}
Vă rugăm să reținețică am specificat Comparable<Car>interfața, nu doar Comparable. Aceasta este o interfață parametrizată, adică trebuie să specificăm clasa asociată specifică. În principiu, puteți elimina <Car>din interfață, dar apoi compararea se va baza pe Objectobiecte în mod implicit. În loc de compareTo(Car o)metodă, clasa noastră va avea:

@Override
   public int compareTo(Object o) {
       return 0;
   }
Desigur, este mult mai ușor pentru noi să lucrăm cu Car. În cadrul compareTo()metodei, implementăm logica noastră pentru compararea mașinilor. Să presupunem că trebuie să le sortăm după anul de fabricație. Probabil ați observat că compareTo()metoda returnează un int, nu un boolean. Nu lăsa acest lucru să te surprindă. Când comparăm două obiecte, există 3 posibilități:
  • а < b
  • a > b
  • a == b.
booleanare doar 2 valori: adevărat și fals, ceea ce nu funcționează bine pentru compararea obiectelor. Cu int, totul este mult mai simplu. Dacă valoarea returnată este > 0, atunci a > b. Dacă rezultatul compareToeste < 0, atunci a < b. Și, dacă rezultatul este == 0, atunci două obiecte sunt egale: a == b. Învățarea clasei noastre să sorteze mașinile după anul de fabricație este ușor:

@Override
public int compareTo(Car o) {
   return this.getManufactureYear() - o.getManufactureYear();
}
Dar ce se întâmplă aici? Luăm un obiect Mașină ( this), obținem anul de fabricație al acestei mașini și scădem din el anul de fabricație al altei mașini (cel cu care obiectul este comparat). Dacă anul de fabricație al primului automobil este mai mare, metoda va returna un int > 0. Aceasta înseamnă că this car >mașina o. În schimb, dacă anul de fabricație al celei de-a doua mașini ( о) este mai mare, atunci metoda va returna un număr negativ, ceea ce înseamnă că o > this. În cele din urmă, dacă sunt egale, atunci metoda va reveni 0. Acest mecanism simplu este deja suficient pentru a sorta colecții de Carobiecte! Nu trebuie să faci nimic altceva. Verifică:

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);
   }
}
Ieșire din consolă:

[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}]
Mașinile sunt sortate așa cum vrem noi! :) Clasa Comparator Java - 2Când ar trebui să folosesc Comparable? Metoda de comparație implementată în Comparablese numește ordonare naturală. Acest lucru se datorează faptului că în compareTo()metodă definiți cel mai comun sau natural mod de a compara obiectele acestei clase. Java are deja o ordonare naturală. De exemplu, Java știe că șirurile de caractere sunt cel mai adesea sortate alfabetic, iar numerele prin creșterea valorii numerice. Prin urmare, dacă apelați sort()metoda pe o listă de numere sau șiruri, acestea vor fi sortate. Dacă programul nostru va compara și sorta de obicei mașinile după anul de fabricație, atunci ar trebui să definim sortarea naturală pentru Mașini folosind interfața Comparable<Car>șicompareTo()metodă. Dar dacă acest lucru nu este suficient pentru noi? Să ne imaginăm că programul nostru nu este atât de simplu. În majoritatea cazurilor, sortarea naturală a mașinilor (pe care am stabilit să fie efectuată pe an de fabricație) ni se potrivește. Dar uneori clienții noștri sunt pasionați de conducere rapidă. Dacă pregătim un catalog de mașini pentru ca ei să le citească, mașinile ar trebui să fie sortate după viteza maximă. Clasa Comparator Java - 3De exemplu, să presupunem că trebuie să sortăm astfel 15% din timp. În mod clar, acest lucru nu este suficient pentru ca noi să setăm Carsortarea naturală a clasei să fie după viteză și nu după anul de fabricație. Dar nu putem ignora 15% dintre clienții noștri. Deci ce facem? O altă interfață ne vine în ajutor aici: Comparator. La fel ca Comparable, este o interfață parametrizată. Care este diferența? Comparableface obiectele noastre „comparabile” și definește cea mai naturală ordine de sortare a acestora, adică ordinea de sortare care va fi folosită în majoritatea cazurilor. Comparatoreste o interfață separată de „comparare”. Dacă trebuie să implementăm un fel de ordine specială de sortare, nu trebuie să intrăm în Carclasă și să schimbăm logica compareTo(). În schimb, putem crea o clasă separată care implementează Comparator și să-l învățăm cum să efectueze sortarea de care avem nevoie!

import java.util.Comparator;

public class MaxSpeedCarComparator implements Comparator<Car> {
  
   @Override
   public int compare(Car o1, Car o2) {
       return o1.getMaxSpeed() - o2.getMaxSpeed();
   }
}
După cum puteți vedea, Comparatoreste destul de simplu. Trebuie să implementăm o singură metodă de interfață: compare(). Ia două Carobiecte ca intrări și compară vitezele lor maxime în mod obișnuit (prin scădere). Ca compareTo(), returnează an int, iar principiul comparației este același. Cum folosim asta? Totul este simplu:

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);
   }
}
Ieșire din consolă:

[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}]
Pur și simplu creăm un obiect comparator și îl transmitem metodei Collections.sort()împreună cu lista de sortat. Când sort()metoda primește un comparator, nu folosește sortarea naturală definită în metoda Carclasei . compareTo()În schimb, aplică algoritmul de sortare definit de comparatorul transmis acestuia. Care sunt avantajele de a face acest lucru? În primul rând, compatibilitatea cu codul existent. Am creat o nouă metodă de sortare specială, păstrând-o pe cea existentă care va fi folosită de cele mai multe ori. Nu ne-am atins Cardeloc de clasă. A fost un Comparable, și așa rămâne:

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()

}
În al doilea rând, flexibilitatea. Putem adăuga oricât de mulți algoritmi de sortare ne dorim. De exemplu, putem sorta mașinile după culoare, viteză, greutate sau de câte ori a fost folosită o mașină în filmele Batman. Tot ce trebuie să facem este să creăm un Comparator. Asta este! Astăzi ați studiat două mecanisme foarte importante pe care le veți folosi adesea în proiecte reale la locul de muncă. Dar, după cum știți, teoria fără practică este nimic. Acum este timpul să vă consolidați cunoștințele și să finalizați câteva sarcini!
Comentarii
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION