CodeGym /Java-Blog /Random-DE /Javas Comparator-Klasse
Autor
Artem Divertitto
Senior Android Developer at United Tech

Javas Comparator-Klasse

Veröffentlicht in der Gruppe Random-DE
Hallo! Heute werden wir über den Vergleich von Objekten sprechen. Javas Comparator-Klasse – 1 Hmm... Aber haben wir dieses Thema nicht schon mehr als einmal besprochen? :/ Wir kennen die ==Funktionsweise des Operators sowie die equals()und- hashCode()Methoden. Der Vergleich ist etwas anders. Früher meinten wir höchstwahrscheinlich „Objekte auf Gleichheit prüfen“. Doch die Gründe, Objekte miteinander zu vergleichen, können ganz unterschiedlich sein! Das offensichtlichste davon ist das Sortieren. Ich denke, wenn man Ihnen sagen würde, dass Sie eine Reihe ArrayList<>von Zahlen oder Zeichenfolgen sortieren sollen, könnten Sie dies ohne Probleme bewältigen:

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);
   }
}
Konsolenausgabe:

[Dasha, Masha, Sasha]
Wenn Sie sich an die CollectionsKlasse und ihre sort()Methode erinnern, gut gemacht! Ich denke, dass Sie auch mit Zahlen keine Probleme haben werden. Hier ist eine anspruchsvollere Aufgabe für Sie:

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);
   }
}
Die Aufgabe ist eigentlich einfach. Wir haben eine CarKlasse und 3 Autoobjekte. Würden Sie bitte die Autos in der Liste sortieren? Sie werden sich wahrscheinlich fragen: „Wie sollen sie sortiert werden?“ Namentlich? Nach Baujahr? Durch Höchstgeschwindigkeit? Ausgezeichnete Frage. Im Moment wissen wir nicht, wie wir die CarObjekte sortieren sollen. Und das weiß Java natürlich auch nicht! CarWenn wir versuchen, eine Liste von Objekten an die Methode zu übergeben Collections.sort(), erhalten wir eine Fehlermeldung:

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);
   }
}
Und wie sollte die Sprache tatsächlich wissen, wie sie Objekte der von Ihnen geschriebenen Klassen sortieren soll? Dies hängt davon ab, was Ihr Programm tun muss. Wir müssen Java irgendwie beibringen, diese Objekte zu vergleichen. Und sie genau so zu vergleichen, wie wir es wollen. Java verfügt dafür über einen speziellen Mechanismus: die ComparableSchnittstelle. Um unsere CarObjekte irgendwie vergleichen und sortieren zu können, muss die Klasse diese Schnittstelle implementieren, die aus einer einzigen Methode besteht 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()

}
bitte beachten Siedass wir die Comparable<Car>Schnittstelle angegeben haben, nicht nur Comparable. Dies ist eine parametrisierte Schnittstelle, das heißt, wir müssen die spezifische zugehörige Klasse angeben. Im Prinzip können Sie sie <Car>aus der Schnittstelle entfernen, der Vergleich basiert dann jedoch Objectstandardmäßig auf Objekten. Anstelle der compareTo(Car o)Methode wird unsere Klasse Folgendes haben:

@Override
   public int compareTo(Object o) {
       return 0;
   }
Natürlich ist es für uns viel einfacher, damit zu arbeiten Car. Innerhalb der compareTo()Methode implementieren wir unsere Logik zum Vergleichen von Autos. Angenommen, wir müssen sie nach Herstellungsjahr sortieren. Sie haben wahrscheinlich bemerkt, dass die compareTo()Methode ein zurückgibt int, kein boolean. Lassen Sie sich davon nicht überraschen. Wenn wir zwei Objekte vergleichen, gibt es drei Möglichkeiten:
  • а < b
  • a > b
  • a == b.
booleanhat nur zwei Werte: wahr und falsch, was zum Vergleichen von Objekten nicht gut funktioniert. Mit intist alles viel einfacher. Wenn der Rückgabewert ist > 0, dann a > b. Wenn das Ergebnis von compareToist < 0, dann a < b. Und wenn das Ergebnis ist == 0, dann sind zwei Objekte gleich: a == b. Unserer Klasse beizubringen, Autos nach Baujahr zu sortieren, ist ein Kinderspiel:

@Override
public int compareTo(Car o) {
   return this.getManufactureYear() - o.getManufactureYear();
}
Aber was ist hier los? Wir nehmen ein Autoobjekt ( this), ermitteln das Herstellungsjahr dieses Autos und subtrahieren davon das Herstellungsjahr eines anderen Autos (desjenigen, mit dem das Objekt verglichen wird). Wenn das Baujahr des ersten Autos höher ist, gibt die Methode einen zurück int > 0. Das bedeutet, dass das this car >Auto o. Wenn umgekehrt das Baujahr des Zweitwagens ( о) größer ist, dann gibt die Methode eine negative Zahl zurück, was bedeutet, dass o > this. Wenn sie schließlich gleich sind, gibt die Methode zurück 0. Dieser einfache Mechanismus reicht uns bereits aus, um Sammlungen von CarObjekten zu sortieren! Sie müssen nichts weiter tun. Hör zu:

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);
   }
}
Konsolenausgabe:

[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}]
Die Autos sind so sortiert, wie wir es wollen! :) Javas Comparator-Klasse – 2Wann sollte ich verwenden Comparable? Die in implementierte Vergleichsmethode Comparablewird als natürliche Reihenfolge bezeichnet. Dies liegt daran, dass Sie in der compareTo()Methode die gebräuchlichste bzw. natürlichste Art des Vergleichs von Objekten dieser Klasse definieren. Java hat bereits eine natürliche Ordnung. Java weiß beispielsweise, dass Zeichenfolgen am häufigsten alphabetisch und Zahlen nach zunehmendem numerischen Wert sortiert werden. Wenn Sie die Methode daher sort()für eine Liste von Zahlen oder Zeichenfolgen aufrufen, werden diese sortiert. Wenn unser Programm normalerweise Autos nach Baujahr vergleicht und sortiert, sollten wir die natürliche Sortierung für Autos mithilfe der Comparable<Car>Schnittstelle und des definierencompareTo()Methode. Was aber, wenn uns das nicht reicht? Stellen wir uns vor, dass unser Programm nicht so einfach ist. In den meisten Fällen kommt uns die natürliche Sortierung der Autos, die wir nach Baujahren festgelegt haben, entgegen. Aber manchmal sind unsere Kunden Liebhaber des schnellen Fahrens. Wenn wir einen Autokatalog zur Durchsicht vorbereiten, sollten die Autos nach Höchstgeschwindigkeit sortiert sein. Javas Comparator-Klasse – 3Angenommen, wir müssen in 15 % der Fälle so sortieren. CarDies reicht eindeutig nicht aus, um die natürliche Sortierung der Klasse auf Geschwindigkeit statt auf Herstellungsjahr festzulegen . Aber wir können 15 % unserer Kunden nicht ignorieren. Also, was machen wir? Hier kommt uns eine weitere Schnittstelle zu Hilfe: Comparator. Es handelt sich genau wie Comparableum eine parametrisierte Schnittstelle. Was ist der Unterschied? Comparablemacht unsere Objekte „vergleichbar“ und definiert ihre natürlichste Sortierreihenfolge, also die Sortierreihenfolge, die in den meisten Fällen verwendet wird. Comparatorist eine separate „Vergleichs“-Schnittstelle. Wenn wir eine spezielle Sortierreihenfolge implementieren müssen, müssen wir nicht in die CarKlasse gehen und die Logik von ändern compareTo(). Stattdessen können wir eine separate Klasse erstellen, die Comparator implementiert, und ihr beibringen, wie die von uns benötigte Sortierung durchgeführt wird!

import java.util.Comparator;

public class MaxSpeedCarComparator implements Comparator<Car> {
  
   @Override
   public int compare(Car o1, Car o2) {
       return o1.getMaxSpeed() - o2.getMaxSpeed();
   }
}
Wie Sie sehen, Comparatorist unser Ansatz ziemlich einfach. Wir müssen nur eine Schnittstellenmethode implementieren: compare(). Es nimmt zwei CarObjekte als Eingaben und vergleicht ihre Maximalgeschwindigkeiten auf die übliche Weise (durch Subtraktion). compareTo()Es gibt wie auch an zurück int, und das Prinzip des Vergleichs ist dasselbe. Wie nutzen wir das? Es ist alles ganz einfach:

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);
   }
}
Konsolenausgabe:

[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}]
Wir erstellen einfach ein Komparatorobjekt und übergeben es Collections.sort()zusammen mit der zu sortierenden Liste an die Methode. Wenn die sort()Methode einen Komparator empfängt, verwendet sie nicht die in der Methode Carder Klasse definierte natürliche Sortierung compareTo(). Stattdessen wendet es den Sortieralgorithmus an, der durch den ihm übergebenen Komparator definiert wird. Welche Vorteile bietet dies? Erstens die Kompatibilität mit vorhandenem Code. Wir haben eine neue, spezielle Sortiermethode entwickelt und gleichzeitig die bestehende beibehalten, die am häufigsten verwendet wird. CarWir haben die Klasse überhaupt nicht berührt . Es war ein Comparable, und so bleibt es:

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

}
Zweitens Flexibilität. Wir können beliebig viele Sortieralgorithmen hinzufügen. Wir können Autos beispielsweise nach Farbe, Geschwindigkeit, Gewicht oder danach sortieren, wie oft ein Auto in Batman-Filmen verwendet wurde. Wir müssen lediglich eine zusätzliche erstellen Comparator. Das ist es! Heute haben Sie zwei sehr wichtige Mechanismen untersucht, die Sie häufig in realen Projekten bei der Arbeit verwenden werden. Aber wie Sie wissen, ist Theorie ohne Praxis nichts. Jetzt ist es an der Zeit, Ihr Wissen zu festigen und einige Aufgaben zu erledigen!
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION