CodeGym/Java blog/Véletlen/A Java Comparator osztálya
John Squirrels
Szint
San Francisco

A Java Comparator osztálya

Megjelent a csoportban
Szia! Ma az objektumok összehasonlításáról fogunk beszélni. A Java Comparator osztálya - 1 Hmm... De nem beszéltünk már többször erről a témáról? :/ Ismerjük az ==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 Collectionsosztá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 Carosztá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 Cartárgyakat. És természetesen ezt a Java sem tudja! Amikor objektumok listáját próbáljuk átadni Cara 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 Comparableinterfé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 Objectalapé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.
booleancsak 2 értéke van: igaz és hamis, ami nem működik jól az objektumok összehasonlításakor. A segítségével intminden sokkal egyszerűbb. Ha a visszatérési érték > 0, akkor a > b. Ha az eredménye , compareToakkor . É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: < 0a < b== 0a == 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! :) A Java Comparator osztálya - 2Mikor használjam Comparable? A ben megvalósított összehasonlítási módszert Comparabletermé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. A Java Comparator osztálya - 3Tegyük fel például, hogy az esetek 15%-ában így kell rendeznünk. CarEz 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. Comparatoregy 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 Carosztá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 Comparatornagyon egyszerű. Csak egy interfész módszert kell megvalósítanunk: compare(). CarBemenetké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 Carosztá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. CarEgyá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!
Hozzászólások
  • Népszerű
  • Új
  • Régi
Hozzászólás írásához be kell jelentkeznie
Ennek az oldalnak még nincsenek megjegyzései