Perché viene Comparableutilizzato Java ? Perché qualcuno dovrebbe implementare Comparablein una classe? Qual è un esempio di vita reale in cui è necessario implementare comparabili?
Perché viene Comparableutilizzato Java ? Perché qualcuno dovrebbe implementare Comparablein una classe? Qual è un esempio di vita reale in cui è necessario implementare comparabili?
Risposte:
Ecco un esempio di vita reale. Si noti che Stringimplementa anche Comparable.
class Author implements Comparable<Author>{
String firstName;
String lastName;
@Override
public int compareTo(Author other){
// compareTo should return < 0 if this is supposed to be
// less than other, > 0 if this is supposed to be greater than
// other and 0 if they are supposed to be equal
int last = this.lastName.compareTo(other.lastName);
return last == 0 ? this.firstName.compareTo(other.firstName) : last;
}
}
dopo..
/**
* List the authors. Sort them by name so it will look good.
*/
public List<Author> listAuthors(){
List<Author> authors = readAuthorsFromFileOrSomething();
Collections.sort(authors);
return authors;
}
/**
* List unique authors. Sort them by name so it will look good.
*/
public SortedSet<Author> listUniqueAuthors(){
List<Author> authors = readAuthorsFromFileOrSomething();
return new TreeSet<Author>(authors);
}
last?
Comparable definisce un ordinamento naturale. Ciò significa che lo stai definendo quando un oggetto dovrebbe essere considerato "minore di" o "maggiore di".
Supponiamo di avere un sacco di numeri interi e di volerli ordinare. È abbastanza facile, basta metterli in una raccolta differenziata, giusto?
TreeSet<Integer> m = new TreeSet<Integer>();
m.add(1);
m.add(3);
m.add(2);
for (Integer i : m)
... // values will be sorted
Ma ora supponiamo di avere un oggetto personalizzato, in cui l'ordinamento ha senso per me, ma non è definito. Diciamo che ho dati che rappresentano i distretti per codice postale con densità di popolazione e voglio ordinarli per densità:
public class District {
String zipcode;
Double populationDensity;
}
Ora il modo più semplice per ordinarli è definirli con un ordinamento naturale implementando Comparable, il che significa che esiste un modo standard per definire questi oggetti da ordinare .:
public class District implements Comparable<District>{
String zipcode;
Double populationDensity;
public int compareTo(District other)
{
return populationDensity.compareTo(other.populationDensity);
}
}
Nota che puoi fare la stessa cosa definendo un comparatore. La differenza è che il comparatore definisce la logica di ordinamento al di fuori dell'oggetto . Forse in un processo separato ho bisogno di ordinare gli stessi oggetti tramite codice postale - in tal caso l'ordinamento non è necessariamente una proprietà dell'oggetto o differisce dall'ordinamento naturale degli oggetti. È possibile utilizzare un comparatore esterno per definire un ordine personalizzato su numeri interi, ad esempio ordinandoli in base al loro valore alfabetico.
Fondamentalmente la logica di ordinamento deve esistere da qualche parte. Quello può essere -
nell'oggetto stesso, se è naturalmente confrontabile (estende i comparabili -eg interi)
fornito in un comparatore esterno, come nell'esempio sopra.
TreeSet<Integer>invece di TreeMap<Integer>, poiché quest'ultimo non esiste, TreeMaps sono sempre <Key,Value>-pairs. A proposito, un ipotetico TreeMap<District, Object>funzionerebbe solo se District implementasse Comparable, giusto?
Citato dal javadoc;
Questa interfaccia impone un ordinamento totale sugli oggetti di ogni classe che la implementa. Questo ordinamento viene definito ordinamento naturale della classe e il metodo compareTo della classe viene definito metodo di confronto naturale.
Gli elenchi (e le matrici) di oggetti che implementano questa interfaccia possono essere ordinati automaticamente da Collections.sort (e Arrays.sort). Gli oggetti che implementano questa interfaccia possono essere usati come chiavi in una mappa ordinata o come elementi in un insieme ordinato, senza la necessità di specificare un comparatore.
Modifica: ..e ha reso il bit importante in grassetto.
Il fatto che una classe implementi Comparablesignifica che puoi prendere due oggetti da quella classe e confrontarli. Alcune classi, come alcune raccolte (funzione di ordinamento in una raccolta) che mantengono gli oggetti per fare affidamento sul fatto che siano comparabili (per ordinare, è necessario sapere quale oggetto è il "più grande" e così via).
La maggior parte degli esempi sopra mostra come riutilizzare un oggetto comparabile esistente nella funzione compareTo. Se si desidera implementare il proprio confronto Per quando si desidera confrontare due oggetti della stessa classe, dire un oggetto AirlineTicket che si desidera ordinare in base al prezzo (meno viene classificato per primo), seguito dal numero di scali (di nuovo, meno è al primo posto), faresti quanto segue:
class AirlineTicket implements Comparable<Cost>
{
public double cost;
public int stopovers;
public AirlineTicket(double cost, int stopovers)
{
this.cost = cost; this.stopovers = stopovers ;
}
public int compareTo(Cost o)
{
if(this.cost != o.cost)
return Double.compare(this.cost, o.cost); //sorting in ascending order.
if(this.stopovers != o.stopovers)
return this.stopovers - o.stopovers; //again, ascending but swap the two if you want descending
return 0;
}
}
Un modo semplice per implementare confronti su più campi è con ComparisonChain di Guava - quindi puoi dire
public int compareTo(Foo that) {
return ComparisonChain.start()
.compare(lastName, that.lastName)
.compare(firstName, that.firstName)
.compare(zipCode, that.zipCode)
.result();
}
invece di
public int compareTo(Person other) {
int cmp = lastName.compareTo(other.lastName);
if (cmp != 0) {
return cmp;
}
cmp = firstName.compareTo(other.firstName);
if (cmp != 0) {
return cmp;
}
return Integer.compare(zipCode, other.zipCode);
}
}
Ad esempio, quando si desidera avere una raccolta o una mappa ordinata
Comparable viene utilizzato per confrontare le istanze della tua classe. Possiamo confrontare le istanze in molti modi, per questo motivo dobbiamo implementare un metodo compareToper sapere come (attributi) vogliamo confrontare le istanze.
Dog classe:package test;
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
Dog d1 = new Dog("brutus");
Dog d2 = new Dog("medor");
Dog d3 = new Dog("ara");
Dog[] dogs = new Dog[3];
dogs[0] = d1;
dogs[1] = d2;
dogs[2] = d3;
for (int i = 0; i < 3; i++) {
System.out.println(dogs[i].getName());
}
/**
* Output:
* brutus
* medor
* ara
*/
Arrays.sort(dogs, Dog.NameComparator);
for (int i = 0; i < 3; i++) {
System.out.println(dogs[i].getName());
}
/**
* Output:
* ara
* medor
* brutus
*/
}
}
Main classe:package test;
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
Dog d1 = new Dog("brutus");
Dog d2 = new Dog("medor");
Dog d3 = new Dog("ara");
Dog[] dogs = new Dog[3];
dogs[0] = d1;
dogs[1] = d2;
dogs[2] = d3;
for (int i = 0; i < 3; i++) {
System.out.println(dogs[i].getName());
}
/**
* Output:
* brutus
* medor
* ara
*/
Arrays.sort(dogs, Dog.NameComparator);
for (int i = 0; i < 3; i++) {
System.out.println(dogs[i].getName());
}
/**
* Output:
* ara
* medor
* brutus
*/
}
}
Ecco un buon esempio su come utilizzare comparabili in Java:
http://www.onjava.com/pub/a/onjava/2003/03/12/java_comp.html?page=2
Quando si implementa l' Comparableinterfaccia, è necessario implementare il metodo compareTo(). È necessario per confrontare gli oggetti, al fine di utilizzare, ad esempio, il metodo di ordinamento della ArrayListclasse. Hai bisogno di un modo per confrontare i tuoi oggetti per poterli ordinare. Quindi hai bisogno di un compareTo()metodo personalizzato nella tua classe in modo da poterlo utilizzare con il ArrayListmetodo di ordinamento. Il compareTo()metodo restituisce -1,0,1.
Ho appena letto un capitolo corrispondente in Java Head 2.0, sto ancora imparando.
OK, ma perché non definire un compareTo()metodo senza implementare un'interfaccia comparabile. Ad esempio una classe Citydefinita dal suo namee temperaturee
public int compareTo(City theOther)
{
if (this.temperature < theOther.temperature)
return -1;
else if (this.temperature > theOther.temperature)
return 1;
else
return 0;
}