Guarda .. sinceramente non riesco più a "seguirti", nel senso che ho letto il tuo ultimo post ma hai detto talmente tante cose che probabilmente sono io che non ho compreso bene i tuoi dubbi.
Quindi cerco adesso di spiegarti come fare una classe del genere, così vediamo se ho capito e magari comprendi meglio anche tu. Procederemo per gradi, così vedi anche i ragionamenti che faccio.
-- PASSO 1 --
Iniziamo con il fare una classe "generica" che contiene un solo valore tipizzato con la type variable, cioè appunto della parametrizzazione generica.
La cosa più banale/basilare è questa:
public class Contenitore<T> {
private T valore;
// ... costruttore/i, metodi pubblici getter/setter per il valore, ecc...
}
Non credo ci sia molto da dire qui. Si può istanziare una parametrizzazione concreta di qualunque tipo, posso fare un Contenitore<Object>, Contenitore<String>, Contenitore<Image> ecc...
Non ci sono wildcard né vincoli (i bound) quindi qualunque tipo è lecito.
-- PASSO 2 --
Ora voglio restringere la istanziazione di una parametrizzazione concreta ai soli tipi che sono Comparable. Cioè il valore contenuto
deve implementare Comparable.
La cosa si risolve semplicemente aggiungendo un bound alla type variabile della classe.
public class Contenitore<T extends Comparable<? super T>> {
private T valore;
// ... costruttore/i, metodi pubblici getter/setter per il valore, ecc...
}
Il perché ho messo
? super T l'ho già spiegato prima. Si può giustificare anche in un altro modo, facendo l'esempio di una ipotetica gerarchia di classi, come quella classica: Frutto poi sotto-classi Mela e Arancia.
Supponiamo di avere:
class Frutto implements Comparable<Frutto> { ... }
class Mela extends Frutto { ... }
class Arancia extends Frutto { ... }
La implementazione di Comparable è in Frutto (magari compara es. sul peso che ha senso averlo in Frutto). Nelle sotto-classi la parametrizzazione di Comparable non si può cambiare. Quindi Mela è Comparable<Frutto> .... NON Comparable<Mela>
Se avessi fatto Contenitore come
public class Contenitore<T extends Comparable<T>>
Allora NON avrei potuto fare un Contenitore<Mela> perché si aspetterebbe che Mela sia Comparable<Mela> ma non è così.
Mentre con
? super la forma diventa più ampia e permette un Contenitore<Mela> anche quando Mela è Comparable<Frutto>.
In questo momento quindi la parametrizzazione concreta di Contenitore è più limitata. Posso fare un Contenitore<String>, Contenitore<Integer> ma NON posso fare es. Contenitore<Object> (Object non è Comparable) né ad esempio Contenitore<Image> (intendo java.awt.Image che idem non è Comparable).
-- PASSO 3 --
Nel passo 2 ho ragionato solo sulla comparabilità del
valore contenuto in Contenitore. Ora ragioniamo sulla comparabilità proprio degli oggetti Contenitore tra di loro.
Quando si fa una classe es. Persona "comparabile", generalmente la si fa così:
public class Persona implements Comparable<Persona> {
private String nome;
......
}
Qui come vedi non ci sono wildcard o bound. Generalmente quello che interessa è che un oggetto Persona sia comparabile SOLO con altri oggetti Persona. Non con altro (che avrebbe poco/nessun senso).
La classe Contenitore però è più complessa della classe Persona, perché Contenitore è una classe "generica" ed ha una type variable. Quindi semplicemente bisogna far rispecchiare questo anche nel implements del Comparable per Contenitore.
public class Contenitore<T extends Comparable<? super T>> implements Comparable<Contenitore<T>> {
private T valore;
// ... costruttore/i, metodi pubblici getter/setter per il valore, ecc...
public int compareTo(Contenitore<T> altroContenitore) {
return getValore().compareTo(altroContenitore.getValore());
}
}
(il getValore l'ho omesso per brevità ma è banale farlo e ci deve essere ovviamente)
A questo punto Contenitore: a) accetta e contiene solo valori comparabili e b) gli oggetti Contenitore sono comparabili tra di loro, chiaramente solo con la stessa parametrizzazione, es. un Contenitore<String> è comparabile solo con un altro Contenitore<String>.
Ho chiarito i tuoi dubbi?