CodeGym/Java blogg/Slumpmässig/Javas komparatorklass
John Squirrels
Nivå
San Francisco

Javas komparatorklass

Publicerad i gruppen
Hej! Idag ska vi prata om att jämföra objekt. Javas komparatorklass - 1 Hmm... Men har vi inte redan pratat om detta ämne mer än en gång? :/ Vi vet hur ==operatören fungerar, samt metoderna equals()och hashCode(). Jämförelse är lite annorlunda. Tidigare menade vi med största sannolikhet "kontrollera objekt för likvärdighet". Men anledningarna till att jämföra föremål med varandra kan vara helt olika! Den mest uppenbara av dessa är sortering. Jag tror att om du blev tillsagd att sortera ett ArrayList<>antal siffror eller strängar, skulle du kunna hantera detta utan problem:
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);
   }
}
Konsolutgång:
[Dasha, Masha, Sasha]
Om du kom ihåg Collectionsklassen och dess sort()metod, bra jobbat! Jag tror att du inte heller kommer att ha några problem med siffror. Här är en mer utmanande uppgift för dig:
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);
   }
}
Uppgiften är faktiskt enkel. Vi har en Carklass och 3 bilobjekt. Skulle du snällt sortera bilarna i listan? Du kommer förmodligen att fråga: "Hur ska de sorteras?" Vid namn? Efter tillverkningsår? Med maximal hastighet? Utmärkt fråga. För tillfället vet vi inte hur vi ska sortera Carföremålen. Och, helt naturligt, vet inte Java det heller! När vi försöker skicka en lista med Carobjekt till Collections.sort()metoden får vi ett felmeddelande:
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);
   }
}
Och faktiskt, hur skulle språket veta hur man sorterar föremål i klasser du har skrivit? Detta beror på vad ditt program behöver göra. Vi måste på något sätt lära Java att jämföra dessa objekt. Och att jämföra dem precis som vi vill. Java har en speciell mekanism för detta: gränssnittet Comparable. För att på något sätt jämföra och sortera våra Carobjekt måste klassen implementera detta gränssnitt, som består av en enda 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änligen noteraatt vi angav Comparable<Car>gränssnittet, inte bara Comparable. Detta är ett parametriserat gränssnitt, det vill säga vi måste ange den specifika tillhörande klassen. I princip kan du ta bort <Car>från gränssnittet, men då kommer jämförelsen att baseras på Objectobjekt som standard. Istället för compareTo(Car o)metoden kommer vår klass att ha:
@Override
   public int compareTo(Object o) {
       return 0;
   }
Naturligtvis är det mycket lättare för oss att arbeta med Car. Inuti compareTo()metoden implementerar vi vår logik för att jämföra bilar. Anta att vi behöver sortera dem efter tillverkningsår. Du har säkert märkt att compareTo()metoden returnerar en int, inte en boolean. Låt inte detta överraska dig. När vi jämför två objekt finns det tre möjligheter:
  • а < b
  • a > b
  • a == b.
booleanhar bara 2 värden: sant och falskt, vilket inte fungerar bra för att jämföra objekt. Med int, är allt mycket enklare. Om returvärdet är , > 0a > b. Om resultatet av compareToär < 0, då a < b. Och om resultatet är == 0, då är två objekt lika: a == b. Att lära vår klass att sortera bilar efter tillverkningsår är enkelt:
@Override
public int compareTo(Car o) {
   return this.getManufactureYear() - o.getManufactureYear();
}
Men vad händer här? Vi tar ett bilobjekt ( this), får denna bils tillverkningsår och subtraherar från det tillverkningsåret för en annan bil (den som objektet jämförs med). Om den första bilens tillverkningsår är större kommer metoden att returnera en int > 0. Det betyder att this car >bilen o. Omvänt, om tillverkningsåret för den andra bilen ( о) är större, kommer metoden att returnera ett negativt tal, vilket betyder att o > this. Slutligen, om de är lika, kommer metoden att returnera 0. Denna enkla mekanism räcker redan för oss att sortera samlingar av Carföremål! Du behöver inte göra något annat. Kolla in det:
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);
   }
}
Konsolutgång:
[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}]
Bilarna är sorterade som vi vill! :) Javas komparatorklass - 2När ska jag använda Comparable? Jämförelsemetoden som implementeras i Comparablekallas naturlig ordning. Detta beror på att compareTo()du i metoden definierar det vanligaste, eller naturliga, sättet att jämföra objekt i denna klass. Java har redan en naturlig ordning. Java vet till exempel att strängar oftast sorteras alfabetiskt och siffror genom att öka numeriskt värde. Därför, om du anropar sort()metoden på en lista med nummer eller strängar, kommer de att sorteras. Om vårt program vanligtvis jämför och sorterar bilar efter tillverkningsår, bör vi definiera den naturliga sorteringen för bilar med hjälp av gränssnittet Comparable<Car>ochcompareTo()metod. Men vad händer om detta inte räcker för oss? Låt oss föreställa oss att vårt program inte är så enkelt. I de flesta fall passar den naturliga sorteringen av bilar (som vi har satt att utföras efter tillverkningsår) oss. Men ibland är våra kunder älskare av snabbkörning. Om vi ​​förbereder en bilkatalog för dem att ta del av, bör bilarna sorteras efter maxhastighet. Javas komparatorklass - 3Anta till exempel att vi behöver sortera så här 15 % av tiden. Detta räcker helt klart inte för att vi ska ställa in Carklassens naturliga sortering på hastighet istället för tillverkningsår. Men vi kan inte ignorera 15 % av våra kunder. Så vad gör vi? Ett annat gränssnitt kommer till vår hjälp här: Comparator. Precis som Comparable, det är ett parametriserat gränssnitt. Vad är skillnaden? Comparablegör våra objekt "jämförbara" och definierar deras mest naturliga sorteringsordning, dvs den sorteringsordning som kommer att användas i de flesta fall. Comparatorär ett separat "jämförande" gränssnitt. Om vi ​​behöver implementera någon sorts speciell sorteringsordning behöver vi inte gå in i klassen Caroch ändra logiken för compareTo(). Istället kan vi skapa en separat klass som implementerar Comparator och lära den hur man utför sorteringen vi behöver!
import java.util.Comparator;

public class MaxSpeedCarComparator implements Comparator<Car> {

   @Override
   public int compare(Car o1, Car o2) {
       return o1.getMaxSpeed() - o2.getMaxSpeed();
   }
}
Som du kan se Comparatorär vår ganska enkel. Vi behöver bara implementera en gränssnittsmetod: compare(). Den tar två Carobjekt som indata och jämför deras maximala hastigheter på vanligt sätt (genom subtraktion). Som compareTo(), den returnerar an int, och jämförelseprincipen är densamma. Hur använder vi detta? Allt är enkelt:
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);
   }
}
Konsolutgång:
[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}]
Vi skapar helt enkelt ett komparatorobjekt och skickar det till Collections.sort()metoden tillsammans med listan som ska sorteras. När sort()metoden tar emot en komparator använder den inte den naturliga sorteringen som definieras i Carklassens compareTo()metod. Istället tillämpar den sorteringsalgoritmen definierad av komparatorn som skickas till den. Vilka är fördelarna med att göra detta? Först, kompatibilitet med befintlig kod. Vi skapade en ny, speciell sorteringsmetod, samtidigt som vi behöll den befintliga som kommer att användas för det mesta. Vi rörde inte Carklassen alls. Det var en Comparable, och så förblir det:
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()

}
För det andra, flexibilitet. Vi kan lägga till så många sorteringsalgoritmer som vi vill. Vi kan till exempel sortera bilar efter färg, hastighet, vikt eller efter hur många gånger en bil har använts i Batman-filmer. Allt vi behöver göra är att skapa en extra Comparator. Det är allt! Idag har du studerat två mycket viktiga mekanismer som du ofta kommer att använda i verkliga projekt på jobbet. Men som ni vet är teori utan praktik ingenting. Nu är det dags att konsolidera dina kunskaper och slutföra några uppgifter!
Kommentarer
  • Populär
  • Ny
  • Gammal
Du måste vara inloggad för att lämna en kommentar
Den här sidan har inga kommentarer än