Szia! Ma az objektumok összehasonlításáról fogunk beszélni.
Hmm... De nem beszéltünk már többször erről a témáról? :/ Ismerjük az
Mikor használjam
Tegyük fel például, hogy az esetek 15%-ában így kell rendeznünk.

==
operátor működését, valamint a equals()
és hashCode()
módszereket. Az összehasonlítás egy kicsit más. Korábban nagy valószínűséggel az "tárgyak egyenlőségének ellenőrzése" alatt értünk. De az objektumok egymással való összehasonlításának okai teljesen eltérőek lehetnek! Ezek közül a legkézenfekvőbb a válogatás. Azt hiszem, ha azt mondanák, hogy rendezzen ArrayList<>
számokat vagy karakterláncokat, akkor ezt gond nélkül kezelné:
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);
}
}
Konzol kimenet:
[Dasha, Masha, Sasha]
Ha emlékszel az Collections
osztályra és annak sort()
módszerére, akkor jó! Szerintem a számokkal sem lesz gond. Itt van egy nagyobb kihívást jelentő feladat az Ön számára:
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);
}
}
A feladat valójában egyszerű. Van egy Car
osztályunk és 3 autó objektumunk. Leválogatnád a listán szereplő autókat? Valószínűleg azt fogja kérdezni: "Hogyan kell őket rendezni?" Név szerint? Gyártási év szerint? Maximális sebességgel? Kiváló kérdés. Jelenleg nem tudjuk, hogyan kell rendezni a Car
tárgyakat. És természetesen ezt a Java sem tudja! Amikor objektumok listáját próbáljuk átadni Car
a metódusnak Collections.sort()
, hibát kapunk:
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);
}
}
És valóban, honnan tudná a nyelv, hogyan kell rendezni az Ön által írt osztályok objektumait? Ez attól függ, mit kell tennie a programnak. Valahogy meg kell tanítanunk a Java-t ezen objektumok összehasonlítására. És összehasonlítani őket úgy, ahogy szeretnénk. A Java-nak van egy speciális mechanizmusa erre: az Comparable
interfész. Ahhoz, hogy valamilyen módon összehasonlíthassuk és rendezzük az objektumainkat Car
, az osztálynak meg kell valósítania ezt a felületet, amely egyetlen metódusból áll: 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()
}
Kérjük, vegye figyelembehogy megadtuk a Comparable<Car>
felületet, nem csak a Comparable
. Ez egy paraméterezett interfész, vagyis meg kell adnunk az adott társított osztályt. Elvileg lehet eltávolítani <Car>
a felületről, de akkor az összehasonlítás Object
alapértelmezés szerint objektumok alapján történik. A metódus helyett compareTo(Car o)
az osztályunkban a következő lesz:
@Override
public int compareTo(Object o) {
return 0;
}
Természetesen sokkal könnyebben dolgozhatunk vele Car
. A compareTo()
módszeren belül megvalósítjuk az autók összehasonlítására vonatkozó logikánkat. Tegyük fel, hogy gyártási év szerint kell rendeznünk őket. Valószínűleg észrevette, hogy a compareTo()
metódus nem a int
, hanem egy boolean
. Ne hagyd, hogy ez meglepjen. Ha két objektumot összehasonlítunk, 3 lehetőség van:
а < b
a > b
a == b
.
boolean
csak 2 értéke van: igaz és hamis, ami nem működik jól az objektumok összehasonlításakor. A segítségével int
minden sokkal egyszerűbb. Ha a visszatérési érték > 0
, akkor a > b
. Ha az eredménye , compareTo
akkor . És ha az eredmény , akkor két objektum egyenlő: . Könnyű megtanítani osztályunkat az autók gyártási év szerinti osztályozására: < 0
a < b
== 0
a == b
@Override
public int compareTo(Car o) {
return this.getManufactureYear() - o.getManufactureYear();
}
De mi folyik itt? Vegyünk egy autó tárgyat ( this
), megkapjuk ennek az autónak a gyártási évét, és levonjuk belőle egy másik autó gyártási évét (amelyhez az objektumot hasonlítják). Ha az első autó gyártási éve nagyobb, a metódus egy int > 0
. Ez azt jelenti, hogy az this car >
autó o
. Ezzel szemben, ha a második autó gyártási éve ( о
) nagyobb, akkor a módszer negatív számot ad vissza, ami azt jelenti, hogy o > this
. Végül, ha egyenlőek, akkor a metódus visszatér 0
. Ez az egyszerű mechanizmus már elegendő ahhoz, hogy tárgygyűjteményeket rendezzünk Car
! Nem kell mást tenned. Nézd meg:
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);
}
}
Konzol kimenet:
[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}]
Az autók úgy vannak szétválogatva, ahogy akarjuk! :) 
Comparable
? A ben megvalósított összehasonlítási módszert Comparable
természetes rendezésnek nevezzük. Ennek az az oka, hogy a metódusban compareTo()
meghatározza az osztály objektumai összehasonlításának leggyakoribb vagy természetes módját. A Java-nak már van természetes sorrendje. Például a Java tudja, hogy a karakterláncokat leggyakrabban ábécé szerint rendezik, a számokat pedig a számértékek növelésével. sort()
Ezért, ha a metódust számok vagy karakterláncok listáján hívja meg , akkor azok rendezve lesznek. Ha a programunk általában az autókat gyártási év szerint hasonlítja össze és rendezi, akkor az autók természetes válogatását a Comparable<Car>
felület és acompareTo()
módszer. De mi van, ha ez nekünk nem elég? Képzeljük el, hogy a programunk nem olyan egyszerű. A legtöbb esetben az autók természetes válogatása (amelyet gyártási évenként állítottunk be) megfelel nekünk. Ügyfeleink azonban néha a gyors vezetés szerelmesei. Ha autókatalógust készítünk, hogy átnézzék, az autókat maximális sebesség szerint kell válogatni. 
Car
Ez nyilvánvalóan nem elég ahhoz, hogy az osztály természetes válogatását sebességre állítsuk be a gyártási év helyett. De nem hagyhatjuk figyelmen kívül ügyfeleink 15%-át. Szóval mit csináljunk? Itt egy másik felület is segítségünkre van: Comparator
. Akárcsak a Comparable
, ez is egy paraméterezett interfész. Mi a különbség? Comparable
"összehasonlíthatóvá" teszi tárgyainkat, és meghatározza azok legtermészetesebb rendezési sorrendjét, vagyis azt a rendezési sorrendet, amelyet a legtöbb esetben használni fognak. Comparator
egy különálló "összehasonlító" felület. Ha valamilyen speciális rendezési sorrendet kell megvalósítanunk, akkor nem kell bemennünk az Car
osztályba és megváltoztatni a logikáját compareTo()
. Ehelyett létrehozhatunk egy külön osztályt, amely megvalósítja a Comparator-t, és megtanítjuk neki a szükséges rendezést!
import java.util.Comparator;
public class MaxSpeedCarComparator implements Comparator<Car> {
@Override
public int compare(Car o1, Car o2) {
return o1.getMaxSpeed() - o2.getMaxSpeed();
}
}
Amint látja, a mi feladatunk Comparator
nagyon egyszerű. Csak egy interfész módszert kell megvalósítanunk: compare()
. Car
Bemenetként két objektumot vesz fel , és a szokásos módon (kivonással) összehasonlítja azok maximális sebességét. Hasonlóan compareTo()
az an -t adja vissza int
, és az összehasonlítás elve ugyanaz. Hogyan használjuk ezt? Minden egyértelmű:
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);
}
}
Konzol kimenet:
[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}]
Egyszerűen létrehozunk egy összehasonlító objektumot, és átadjuk a Collections.sort()
metódusnak a rendezendő listával együtt. Amikor a sort()
metódus komparátort kap, nem használja az Car
osztály compareTo()
metódusában meghatározott természetes rendezést. Ehelyett a neki átadott összehasonlító által meghatározott rendezési algoritmust alkalmazza. Milyen előnyei vannak ennek? Először is, kompatibilitás a meglévő kóddal. Létrehoztunk egy új, speciális válogatási módszert, megtartva a meglévőt, amelyet legtöbbször alkalmazni fogunk. Car
Egyáltalán nem nyúltunk az osztályhoz. Ez volt Comparable
, és így marad:
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()
}
Másodszor a rugalmasság. Tetszőleges számú rendezési algoritmust adhatunk hozzá. Például sorba rendezhetjük az autókat szín, sebesség, tömeg vagy aszerint, hogy hányszor használtak egy autót a Batman-filmekben. Nincs más dolgunk, mint létrehozni egy további Comparator
. Ez az! Ma két nagyon fontos mechanizmust tanulmányoztál, amelyeket gyakran fogsz használni valós munkád során. De mint tudod, az elmélet gyakorlat nélkül semmi. Itt az ideje, hogy megszilárdítsa tudását, és elvégezzen néhány feladatot!
GO TO FULL VERSION