PDA

Visualizza la versione completa : [java] Comparator


maurizio2
16-03-2005, 15:47
Non sto riuscendo a capire come implementare
l'interfaccia Comparator,
ammettiamo io devo ordinare un array di oggetti:


Object[] myObj = new Object[10];
java.util.Arrays.sort(Object[] myObj, Comparator c);


So che l'interfaccia dichiara due metodi:


boolean equals();
int compare()


Chi mi puo' fare un esempio molto semplice
di come implementare questa interfaccia??

Ciao :fagiano:

LeleFT
16-03-2005, 16:45
Ho notato che Comparator è molto simile a Comparable che io ho proficuamente utilizzato più volte. In effetti Comparator richiede anche l'implementazione del metodo equals() che non è richiesta per Comparable.
Se il tuo scopo è quello di poter ordinare un array di oggetti, allora ti consiglio di implementare Comparable (ti risparmi un metodo), comunque il metodo principale è uguale (cambia solamente il nome: per Comparator si chiama compare(), mentre per Comparable si chiama compareTo()).
Quello che devi fare tu è implementare il metodo compare() in modo che restituisca un intero. Il numero intero che viene restituito deve seguire le seguenti regole:

1) Deve essere negativo se il primo oggetto è minore del secondo oggetto;

2) Deve essere uguale a 0 se i due oggetti sono uguali

3) Deve essere maggiore di 0 se il primo oggetto è maggiore del secondo oggetto;
Esempio: prendiamo questo piccolo esempio:


String s1 = "Abcd";
String s2 = "Dcba";

compare(s1, s2) --> ritorna un numero negativo
compare(s1, s1) --> ritorna 0
compare(s2, s1) --> ritorna un numero positivo

Vediamo, quindi, un esempio di ordinamento, con una classe che implementa Comparable:


public class MioOggetto implements Comparator {
private int[] mioDato;
public MioOggetto() { mioDato = new int[2]; }
public int [] getDato() { return mioDato; }
public int compare(Object o1, Object o2) {
/* Questo metodo effettua un ordinamento sulle coppie di interi
* L'ordinamento è il seguente:
* (A, B) < (C, D) se e solo se (A < C) oppure ((A = C) e (B < D))
* (A, B) = (C, D) se e solo se (A = C) e (B = D)
* altrimenti (A, B) > (C, D)
*/

MioOggetto mo1 = (MioOggetto) o1;
MioOggetto mo2 = (MioOggetto) o2;
int [] altroDato1 = mo1.getDato();
int [] altroDato2 = mo2.getDato();
return (altroDato1[0] == altroDato2[0]) ?
altroDato1[1]-altroDato2[1] :
altroDato1[0]-altroDato2[0];
}
}

Non ho fatto delle prove ma dovrebbe andare.

A questo punto, se hai un array di MioOggetto, puoi passarli ad Arrays.sort() in questo modo:


MioOggetto [] array = ...;
Arrays.sort( array );

Ciao. :ciauz:

maurizio2
16-03-2005, 17:26
ok Comparable e il suo utilizzo l'ho ben compreso,
quindi posso dedurre che Comparator serve a
generalizzare il cocetto di confronto tra due
oggetti(minore o maggiore o uguale).

Comparable e' un interfaccia che definisce un
unico metodo (compareTo()).

Mentre in Comparator i metodi sono due:
boolean equals();//se due oggetti sono uguali
int compare();//confronto di tipo alfabetico

Ma essendo Comparator un'interfaccia
non deve la classe che lo implementa
ridefinire entrambi i metodi??

Quindi il tuo esempio dovrebbe suscitare
una protesta da parte del compilatore.
Cmq non ho provato ancora quindi cio' che
ho detto e' del tutto opinabile.
:master:

LeleFT
16-03-2005, 17:42
Originariamente inviato da maurizio2
ok Comparable e il suo utilizzo l'ho ben compreso,
quindi posso dedurre che Comparator serve a
generalizzare il cocetto di confronto tra due
oggetti(minore o maggiore o uguale).

Comparable e' un interfaccia che definisce un
unico metodo (compareTo()).

Mentre in Comparator i metodi sono due:
boolean equals();//se due oggetti sono uguali
int compare();//confronto di tipo alfabetico

Ma essendo Comparator un'interfaccia
non deve la classe che lo implementa
ridefinire entrambi i metodi??

Quindi il tuo esempio dovrebbe suscitare
una protesta da parte del compilatore.
Cmq non ho provato ancora quindi cio' che
ho detto e' del tutto opinabile.
:master:
Hai perfettamente ragione. Mi sono scordato di implementare il metodo equals() e ciò susciterà senza dubbio delle sonore proteste da parte del compilatore. La definizione del metodo equals(), comunque, è molto più sempilce del previsto:


public class MioOggetto implements Comparator {
...
public boolean equals(Object o) {
boolean risultato = false;
if ( o instanceof MioOggetto) {
MioOggetto mo = (MioOggetto) o;
int [] dato = mo.getDato();
risultato = (dato[0] == mioDato[0]) && (dato[1] == mioDato[1]);
}
return risultato;
}
}

Credo che si potesse anche ricorrere al metodo equals() di Object, ma non ne sono proprio sicuro (basta provare):


public boolean equals(Object o) {
return super.equals(o);
}

Ciao. :ciauz:

maurizio2
16-03-2005, 17:50
Si equals() e' anche in Object
ma implementando Comparator
dovrebbe sopravvenire su quello ereditato
da Object(premettendo sempre l'opinabilita').
Dimmi se mi sbaglio...

PS
Dai un po' alla volta sto imparando anch'io :)

LeleFT
16-03-2005, 18:05
Ho appena provato e funziona, anche se i risultati non sono esattamente quelli attesi! :)

La documentazione di Comparator, comunque, afferma (giustamente) che le classi che implementano tale interfaccia dovrebbero ridefinire il metodo equals() senza far ricorso al metodo omonimo fornito dalla classe Object, in quanto quest'ultimo metodo dovrebbe essere inteso solo come misura di confronto.

E' per questo che i risultati non tornano. Prendiamo, ad esempio, il seguente programma (ho aggiungo un costruttore alla classe MioOggetto di prima):


MioOggetto m1 = new MioOggetto(2, 3);
MioOggetto m2 = new MioOggetto(2, 3);

System.out.println( m1.equals(m2) );

Se ridefiniamo il metodo equals() in modo che esso utilizzi il metodo equals() di Object, questo programma stampa false.

Dal punto di vista semantico, comunque, questo potrebbe non soddisfarci: tutto sommato i due oggetti rappresentano la stessa coppia!

Ecco perchè è bene ridefinire il metodo equals() nel modo che ho descritto precedentemente (senza ricorrere a super.equals() ).


Ciao. :ciauz:

maurizio2
16-03-2005, 18:16
Ok adesso mi e' chiara la differenza
tra le due interfacce(Comparator & Comparable),
devo imparare anche io....

Ritornando all'esempio di prima


public class MioOggetto implements Comparator {
...
public boolean equals(Object o) {
boolean risultato = false;
if ( o instanceof MioOggetto) {
MioOggetto mo = (MioOggetto) o;
int [] dato = mo.getDato();
risultato = (dato[0] == mioDato[0]) && (dato[1] == mioDato[1]);
}
return risultato;
}
}




non si potrebbe scrivere:


if(o.getClass().getName().equals(MioOggetto)){...}

Premetto la leggittimita' di instanceof perche'
sappiamo qui con certezza l'origine del dato.

LeleFT
16-03-2005, 18:24
Originariamente inviato da maurizio2
Ok adesso mi e' chiara la differenza
tra le due interfacce(Comparator & Comparable),
devo imparare anche io....

Ritornando all'esempio di prima
non si potrebbe scrivere:


if(o.getClass().getName().equals(MioOggetto)){...}

Premetto la leggittimita' di instanceof perche'
sappiamo qui con certezza l'origine del dato.
Penso sia più corretto così :) :


if(o.getClass().getName().equals("MioOggetto")){...}

Comunque dipende: se la tua classe non fa parte di alcun package, allora non hai problemi, altrimenti dovresti specificare anche tutto il package. Esempio, se sappiamo che l'oggetto passato è un Integer, che fa parte del package java.lang:


if (o.getClass().getName().equals("java.lang.Integer")) {...}

Diciamo, quindi, che la parola chiave instanceof è più semplice da usare.


Ciao. :ciauz:

LeleFT
16-03-2005, 18:24
Sbagliato a cliccare.

maurizio2
16-03-2005, 18:36
Era solo per capire...
Cmq ho un libro pieno zeppo di errori
e devo ammettere che e' un bene,
il testo riporta l'esempio senza virgolette
e ho corretto l'errore e volevo conferma....
getName() restituisce una stringa del nome della
classe di appartenenza.


Potresti dire di provare di persona gli esempi
ma io uso gia' digitare tutti gli esempi del libro a mano
ma credo che teorizzare a parole gli esempi
le cose si capiscano meglio!!!

ciao :ciauz:

Loading