
Originariamente inviata da
newutente
quindi il vantaggio delle istruzioni viste in precedenza è che è possibile sfruttare il polimorfismo
Sì, i "bound" nei generics sono stati introdotti proprio per fornire una "sorta" di polimorfismo anche sulle parametrizzazioni. Il "vero" polimorfismo è quello ovviamente dovuto alla ereditarietà tra classi, che ormai dovresti aver acquisito.
Ma con i bound si ha una specie di polimorfismo che permette maggior libertà con i generics che, è bene ricordare, sono trattati solo a livello di sorgente/compilazione e sono invarianti (mentre un String[] è-un Object[], un List<String> NON è un List<Object>).
Il modo di uso di extends/super con i wildcard è quello che il libro "Java Generics and Collections" chiama The Get and Put Principle. Con un extends puoi solo "estrarre" un valore (in pratica da un tipo di ritorno di un metodo) e con super puoi solo inserire un valore (un argomento di un metodo).
Se devi estrarre E inserire, non va usato né extends né super.

Originariamente inviata da
newutente
come è possibile allora che un metodo del genere
codice:
public void print(List <? extends Number> list) {
for(Iterator<? extends Number> i = list.iterator(); i.hasNext(); ) {
System.out.println(i.next());
}
}
compila senza problemi?
Certo, compila senza problemi. Stai solo estraendo non inserendo (passando qualcosa in argomento).

Originariamente inviata da
newutente
codice:
List<? extends Number> lista = new ArrayList<Integer>;
oggetto.print(lista);
ma anche:
codice:
List<? extends Number> lista = new ArrayList<Double>;
oggetto.print(lista);
Giusto?
Tecnicamente corretto. Ma avere la variabile 'lista' con il bound in extends è poco utile .... non puoi inserire nulla! Quindi almeno la variabile mettila uguale alla parametrizzazione concreta (ovvero List<Integer>).
Ti faccio un esempio davvero lampante con super. Immagina un metodo che vuole inserire un range di interi in una lista. Senza i bound si potrebbe fare:
codice:
public static void addIntRange(List<Integer> lista, int min, int max) {
for (int n = min; n <= max; n++) {
lista.add(n); // autoboxing int -> Integer
}
}
Il problema è che al metodo posso passare solo un (Xyz)List<Integer> ... non posso passare una lista es. di <Number> o <Object>. Che sarebbero sensati perché entrambi possono lecitamente contenere dei Integer.
Se cambio il parametro e lo metto List<Object> lista il metodo continua a compilare/funzionare ma posso passare solo una lista <Object> ... non <Number> o <Integer> (invarianza!).
Insomma è molto (troppo) rigido.
Allora entra in gioco un bounded wildcard con super:
codice:
public static void addIntRange(List<? super Integer> lista, int min, int max) {
for (int n = min; n <= max; n++) {
lista.add(n); // autoboxing int -> Integer
}
}
Qui devo mettere come bound Integer. Visto che realmente sto passando dei Integer, è l'unico tipo che mi garantisce che qualunque sia la parametrizzazione concreta usata nel chiamante, è lecito inserire dei Integer.
Ora posso passare List<Integer> o List<Number> o List<Object>. Ovviamente non es. List<String> o List<Date> sono fuori dal bound (e nemmeno in relazione con Integer) e non avrebbero senso (e il compilatore lo "sa").