Razlika između Java Comparable i Comparator
Prilikom učenja reda prioriteta ranije smo pomenuli Comparable i Comparator, pa ćemo u ovom članku nastaviti iz ugla intervjuera i razmotriti ih zajedno.
Tog dana, Xiao Er je otišao na intervju u Mafengwo, a intervjuer stari Wang mu je odmah postavio pitanje: Koja je razlika između Comparable i Comparator? Xiao Er je jedva suzdržao smeh, jer je još pre tri godine, odnosno 2021. godine, video to pitanje u "Ergeovom putu napredovanja u Javi"😆.
Comparable i Comparator su dva Java interfejsa; već iz imena možemo pročitati njihovu sličnost: na neki način porede dva objekta.
Ali u čemu je zapravo razlika između njih? Pođite sa mnom, napredujte pobeđujući "čudovišta"!
01,Comparable
Definicija Comparable interfejsa je vrlo jednostavna, izvorni kod je prikazan ispod.
public interface Comparable<T> {
int compareTo(T t);
}Ako klasa implementira Comparable interfejs (potrebno je uraditi samo jedno — redefinisati compareTo() metod), onda se objekti koje ona kreira mogu porediti prema pravilima koja ste sami zadali. Evo primera.
public class Cmower implements Comparable<Cmower> {
private int age;
private String name;
public Cmower(int age, String name) {
this.age = age;
this.name = name;
}
@Override
public int compareTo(Cmower o) {
return this.getAge() - o.getAge();
}
public static void main(String[] args) {
Cmower wanger = new Cmower(19,"Chenmo Wang Er");
Cmower wangsan = new Cmower(16,"Chenmo Wang San");
if (wanger.compareTo(wangsan) < 0) {
System.out.println(wanger.getName() + " je mlađi i perspektivniji");
} else {
System.out.println(wangsan.getName() + " je mlađi i perspektivniji");
}
}
}U gornjem primeru kreirao sam klasu Cmower koja ima dva polja: age i name. Klasa Cmower implementira Comparable interfejs i redefiniše compareTo() metod.
Rezultat programa je "Chenmo Wang San je mlađi i perspektivniji", jer je tri godine mlađi od Chenmo Wang Er-a. Koji je dokaz za taj rezultat?
Dokaz leži u compareTo() metodu — povratna vrednost ovog metoda može biti negativan broj, nula ili pozitivan broj, što označava da je ovaj objekat po pravilima sortiranja manji, jednak ili veći od objekta sa kojim se poredi. Ako se tip navedenog objekta ne može porediti sa ovim objektom, izaziva se ClassCastException izuzetak (otkako postoji generički tipovi, takve situacije su retke).
02,Comparator
Definicija Comparator interfejsa je mnogo složenija u poređenju sa Comparable, ali su ključna samo dva metoda — pogledajmo izvorni kod.
public interface Comparator<T> {
int compare(T o1, T o2);
boolean equals(Object obj);
}Povratna vrednost prvog metoda compare(T o1, T o2) može biti negativan broj, nula ili pozitivan broj, što označava da je prvi objekat manji, jednak ili veći od drugog objekta.
Drugi metod equals(Object obj) zahteva da se prosledi Object kao argument i proverava da li je taj Object u skladu sa Comparator-om.
Ponekad želimo da klasa zadrži svoj prvobitni oblik i da ne implementira aktivno Comparable interfejs, ali nam je ipak potrebno da ih poredimo — šta onda?
Ovde na scenu stupa Comparator; pogledajmo primer.
1)Klasa Cmower u originalnom obliku.
public class Cmower {
private int age;
private String name;
public Cmower(int age, String name) {
this.age = age;
this.name = name;
}
}Klasa Cmower ima dva polja: age i name, što znači da se može sortirati po age ili po name.
2)Zatim pogledajmo implementacionu klasu Comparator interfejsa.
public class CmowerComparator implements Comparator<Cmower> {
@Override
public int compare(Cmower o1, Cmower o2) {
return o1.getAge() - o2.getAge();
}
}Poredi prema age. Naravno, može se implementirati i drugi komparator koji vrši prirodno sortiranje prema name, kao u primeru ispod.
public class CmowerNameComparator implements Comparator<Cmower> {
@Override
public int compare(Cmower o1, Cmower o2) {
if (o1.getName().hashCode() < o2.getName().hashCode()) {
return -1;
} else if (o1.getName().hashCode() == o2.getName().hashCode()) {
return 0;
}
return 1;
}
}3)Zatim pogledajmo klasu za testiranje.
Cmower wanger = new Cmower(19,"Chenmo Wang Er");
Cmower wangsan = new Cmower(16,"Chenmo Wang San");
Cmower wangyi = new Cmower(28,"Chenmo Wang Yi");
List<Cmower> list = new ArrayList<>();
list.add(wanger);
list.add(wangsan);
list.add(wangyi);
list.sort(new CmowerComparator());
for (Cmower c : list) {
System.out.println(c.getName());
}Kreirana su tri objekta, sa različitim age i različitim name, i dodata su u List. Zatim se koristi sort() metod Liste za sortiranje; pogledajmo rezultat.
Chenmo Wang San
Chenmo Wang Er
Chenmo Wang YiTo znači da je Chenmo Wang San mlađi od Chenmo Wang Er-a, pa je na prvom mestu; Chenmo Wang Yi je stariji od Chenmo Wang Er-a, pa je na trećem mestu. Potpuno se poklapa sa našim očekivanjima.
Iskoristimo ovu priliku da pogledamo izvorni kod sort metoda:
public void sort(Comparator<? super E> c) {
// čuva vrednost modCount trenutnog reda, radi provere da li je sort operacija nelegalna
final int expectedModCount = modCount;
// poziva Arrays.sort da sortira niz elementData, koristeći prosleđeni komparator c
Arrays.sort((E[]) elementData, 0, size, c);
// proverava da li je modCount izmenjen tokom operacije, a ako jeste, baca izuzetak istovremenih izmena
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
// povećava vrednost modCount, što znači da je red izmenjen
modCount++;
}Može se videti da je argument zapravo Comparator interfejs, i koristi generički tip Comparator<? super E> c.
03,Koji onda koristiti?
Pomoću prethodna dva primera možemo uporediti razliku između Comparable i Comparator:
- Klasa koja implementira Comparable interfejs znači da se njeni objekti mogu direktno porediti (sortirati), ali postoji samo jedan način poređenja (sortiranja) — vrlo jednostrano.
- Ako klasa želi da zadrži svoj oblik, a potrebno joj je poredenje (sortiranje) na različite načine, može prilagoditi komparator (implementirati Comparator interfejs).
- Comparable interfejs se nalazi u paketu
java.lang, dok seComparatorinterfejs nalazi u paketujava.util— nisu prava braća, ali mogu proći kao bratići.
Navedimo možda ne sasvim primeran primer. Želim da odem iz Luoyanga u Peking da vidim Veliki zid i iskusim osećaj junaka; mogu ili avionom ili brzim vozom; ali za Sun Wukonga je dovoljno jedan okretaj glavom. Koja je razlika između mene i Sun Wukonga?
Sun Wukong je sam implementirao Comparable interfejs (u njegovo vreme nije bilo aviona ni brzog voza, nije imao izbora), dok ja mogu da se oslonim na Comparator interfejs (moderna prevozna sredstva).
Dobro, o Comparable-u i Comparator-u ćemo pričati toliko. Ukratko, ako sortiranje objekata treba da bude zasnovano na prirodnom redosledu, izaberite Comparable; ako je potrebno sortirati po različitim svojstvima objekta, izaberite Comparator.
