ciao a tutti...
ho un dubbio sulle generics di java...
che differenza c'è nel fare:
o nel fare:codice:class PincoPallino <? extends UnaAltraClasse> {...}
codice:class PincoPallino <T extends UnaAltraClasse> {...}
ciao a tutti...
ho un dubbio sulle generics di java...
che differenza c'è nel fare:
o nel fare:codice:class PincoPallino <? extends UnaAltraClasse> {...}
codice:class PincoPallino <T extends UnaAltraClasse> {...}
Nell'anno 1968 è bastata la potenza di due Commodore 64 per lanciare con successo una navicella sulla Luna; nell'anno 2007 ci vogliono la potenza di un processore quad core 3.30 GHz e 3 Gb di RAM (requisiti minimi ufficiali) per utilizzare Windows Vista. Qualcosa deve essere andato storto!
Sbagliato sintatticamente ... non può compilare perché il "wildcard" ? non può stare lì dove l'hai messo.Originariamente inviato da Hysoka
codice:class PincoPallino <? extends UnaAltraClasse> {...}
Corretto. Definisce una classe generica che ha un tipo parametrico T con la restrizione che quel T, quando verrà fatta una istanziazione "concreta", sia di tipo UnaAltraClasse o suo sottotipo.Originariamente inviato da Hysoka
codice:class PincoPallino <T extends UnaAltraClasse> {...}
codice:class PincoPallino<T extends Number> { ..... } ... PincoPallino<Integer> pp = new PincoPallino<Integer>(); // OK corretto: Integer è un sottotipo di Number PincoPallino<String> pp = new PincoPallino<String>(); // NO errore: String non è un sottotipo di Number
Andrea, andbin.dev – Senior Java developer – SCJP 5 (91%) • SCWCD 5 (94%)
java.util.function Interfaces Cheat Sheet — Java Versions Cheat Sheet
è proprio questo quello che non riesco a capire...a cosa servono questi wildcards?
Nell'anno 1968 è bastata la potenza di due Commodore 64 per lanciare con successo una navicella sulla Luna; nell'anno 2007 ci vogliono la potenza di un processore quad core 3.30 GHz e 3 Gb di RAM (requisiti minimi ufficiali) per utilizzare Windows Vista. Qualcosa deve essere andato storto!
I wildcard sono stati introdotti per offrire una specie di "polimorfismo" anche sui tipi parametrici.Originariamente inviato da Hysoka
è proprio questo quello che non riesco a capire...a cosa servono questi wildcards?
I generics sono stati implementati tramite una tecnica che si chiama "erasure" e per via di questo è stato deciso di rendere i tipi parametrici "invarianti". Un esempio per chiarire: un ArrayList<Number> non è un ArrayList<Object>!! (nonostante Number è un Object).
Se questa cosa fosse permessa, non avendo informazioni sul tipo parametrico a runtime ("erasure"), prova a immaginare cosa potrebbe succedere....codice:ArrayList<Number> numArr = new ArrayList<Number>(); ArrayList<Object> objArr = numArr; // NOOO, errore
Il fatto che i tipi parametrici sono invarianti ovviamente è stato visto come un limite. Ecco quindi che sono stati introdotti i wildcard (che hanno regole molto particolari e complesse).
A questo punto potresti chiederti: posso inserire un String usando objArr?? La risposta è no! Il wildcard indica: "non so di che tipo è". Con l'extends che dice: "ma sicuramente è di un tipo Object o suo sottotipo".codice:ArrayList<Number> numArr = new ArrayList<Number>(); ArrayList<? extends Object> objArr = numArr; // SI
Se non si sa di che tipo è, chiaramente non si può inserire nulla.
Ora potresti chiederti a cosa serve un wildcard. Bene, l'esempio pratico e lampante è nella interfaccia Collection<E> che ha un metodo:
boolean addAll(Collection<? extends E> c)
Se hai una Collection<Number>, puoi aggiungere alla collezione tutti gli elementi in una Collection<Number> ma anche Collection<Integer> o Collection<Double>. Perché è logico. E con il wildcard è possibile.
(piccola nota: complicando un pochino la dichiarazione di addAll si poteva evitare l'uso del wildcard ma con il wildcard è decisamente più chiaro e semplice).
Andrea, andbin.dev – Senior Java developer – SCJP 5 (91%) • SCWCD 5 (94%)
java.util.function Interfaces Cheat Sheet — Java Versions Cheat Sheet
perdona la mia perseveranza, ma io non ci vedo niente di strano nel fare quel codice.Originariamente inviato da andbin
Se questa cosa fosse permessa, non avendo informazioni sul tipo parametrico a runtime ("erasure"), prova a immaginare cosa potrebbe succedere....codice:ArrayList<Number> numArr = new ArrayList<Number>(); ArrayList<Object> objArr = numArr; // NOOO, errore
ma tutto quello che inserisco non lo posso usare come Object? O peggio, castarlo?A questo punto potresti chiederti: posso inserire un String usando objArr?? La risposta è no! Il wildcard indica: "non so di che tipo è". Con l'extends che dice: "ma sicuramente è di un tipo Object o suo sottotipo".codice:ArrayList<Number> numArr = new ArrayList<Number>(); ArrayList<? extends Object> objArr = numArr; // SI
Se non si sa di che tipo è, chiaramente non si può inserire nulla.
Nell'anno 1968 è bastata la potenza di due Commodore 64 per lanciare con successo una navicella sulla Luna; nell'anno 2007 ci vogliono la potenza di un processore quad core 3.30 GHz e 3 Gb di RAM (requisiti minimi ufficiali) per utilizzare Windows Vista. Qualcosa deve essere andato storto!
Se ... e ripeto se quella assegnazione fosse permessa allora si potrebbe inserire un String in un ArrayList<Object> che in realtà farebbe riferimento ad un ArrayList<Number>. E senza avere alcun errore/warning in compilazione!!Originariamente inviato da Hysoka
perdona la mia perseveranza, ma io non ci vedo niente di strano nel fare quel codice.
E tutti questi bei discorsi sui generics e sulla type-safety andrebbero a farsi friggere!!
Tutto il problema, a monte della proibizione di quell'assegnamento, è la "erasure". A runtime la collezione è solo un ArrayList e basta, non c'è scritto da nessuna parte (né all'interno della collezione né altrove) che è di Object o String o altro.
E per completare la discussione c'è da dire che si possono comunque combinare casini. Sfruttando il "raw type".
Ma almeno il compilatore emette un warning:codice:ArrayList<Number> numArr = new ArrayList<Number>(); ArrayList arr = numArr; // OK, nessun errore arr.add("pippo"); // warning!!!
warning: [unchecked] unchecked call to add(E) as a member of the raw type java.util.ArrayList
Come a dire: "guarda che stai facendo qualcosa che probabilmente può dare problemi". E poi appunto sono affari del programmatore ....
Certo ... questo sicuramente.Originariamente inviato da Hysoka
ma tutto quello che inserisco non lo posso usare come Object? O peggio, castarlo?
Ma qui non si stava parlando di cosa contengono le collezioni. Ma di come il wildcard (eventualmente con extends/super) fornisce una forma di "polimorfismo" sul tipo parametrico!!!codice:ArrayList<Number> numArr = new ArrayList<Number>(); // .... Object o = numArr.get(0);
Faccio un altro esempio: voglio realizzare un metodo che inserisce un certo numero di valori casuali interi in una collezione. Senza il wildcard si dovrebbe fare:
È chiaramente limitato ... posso solo passare un List<Integer> (es. ArrayList<Integer> o LinkedList<Integer>). Non posso passare un ArrayList<Number> o ArrayList<Object>.codice:public static void addRandom(List<Integer> lista, int count) { Random r = new Random(); while (count-- > 0) { lista.add(r.nextInt()); } }
Anche se a rigor di logica non sarebbe sbagliato (un Integer può stare benissimo in un ArrayList<Number> o ArrayList<Object>!!!).
Con un "lower bounded" wildcard:
Si può passare un ArrayList<Number> o ArrayList<Object>. Il 'super' indica proprio che il tipo della collezione accettato può essere Integer o un suo super-tipo.codice:public static void addRandom(List<? super Integer> lista, int count) { Random r = new Random(); while (count-- > 0) { lista.add(r.nextInt()); } }
Andrea, andbin.dev – Senior Java developer – SCJP 5 (91%) • SCWCD 5 (94%)
java.util.function Interfaces Cheat Sheet — Java Versions Cheat Sheet
ma in pratica java generics sarebbero una forma analoga ai templates di c++?
il polimorfismo non riguarda i metodi e gli attributi nell'ereditarietà? Java non avendo le funzioni virtual e i puntatori come fa a scegliere in maniera dinamica tra un metodo o un altro
$Pippo... la variabile preferita dall'ingegnere!
Concettualmente sì, anche se ovviamente la implementazione e le regole sono parecchio diverse.Originariamente inviato da Cosmy
ma in pratica java generics sarebbero una forma analoga ai templates di c++?
A dire il vero in Java tutte le invocazioni di metodi di istanza (salvo alcuni casi) sono "virtuali".Originariamente inviato da Cosmy
il polimorfismo non riguarda i metodi e gli attributi nell'ereditarietà? Java non avendo le funzioni virtual e i puntatori come fa a scegliere in maniera dinamica tra un metodo o un altro
Leggi qui cosa dicevo del binding statico/dinamico.
Andrea, andbin.dev – Senior Java developer – SCJP 5 (91%) • SCWCD 5 (94%)
java.util.function Interfaces Cheat Sheet — Java Versions Cheat Sheet
Vediamo se ho capito bene...se volessi fare una list (per esempio) di 'numeri', si dovrebbe fare
ArrayList<? extends Number> al = new ArrayList<? extends Number>();
e qui posso piazzare double, float, int, etc.? Ovviamente, usando le classi wrapper
Nell'anno 1968 è bastata la potenza di due Commodore 64 per lanciare con successo una navicella sulla Luna; nell'anno 2007 ci vogliono la potenza di un processore quad core 3.30 GHz e 3 Gb di RAM (requisiti minimi ufficiali) per utilizzare Windows Vista. Qualcosa deve essere andato storto!
No!! Innanzitutto il wildcard (bounded o unbounded che sia .. non importa) non può stare al livello "top" nella espressione della istanziazione di una classe (la parte new Blabla...).Originariamente inviato da Hysoka
Vediamo se ho capito bene...se volessi fare una list (per esempio) di 'numeri', si dovrebbe fare
ArrayList<? extends Number> al = new ArrayList<? extends Number>();
codice:ArrayList<? extends Number> al = new ArrayList<? extends Number>(); // NO ArrayList<? extends Number> al = new ArrayList<Number>(); // OK ArrayList<Vector<?>> al = new ArrayList<Vector<?>>(); // OK (il ? non è al "top" ma più interno)Per chiarire bene (perché credo/deduco che non ti sia ancora completamente chiaro):Originariamente inviato da Hysoka
e qui posso piazzare double, float, int, etc.? Ovviamente, usando le classi wrapper
1) Una cosa è il tipo di oggetti che si possono usare con un certo tipo parametrico.
Esempio:
Un ArrayList<Number> può tranquillamente contenere Integer, Double, Long, BigDecimal, ecc... Tutto ciò che è un Number.
codice:ArrayList<Number> arr = new ArrayList<Number>(); arr.add(new Integer(12)); // OK arr.add(new Double(20.34)); // OK
2) Un'altra cosa è la assegnazione di un tipo parametrizzato (con una istanziazione di un tipo "concreto" es. ArrayList<String> o con una istanziazione con wildcard es. ArrayList<? extends Number>) ad un tipo più generico.
Esempio:
ArrayList<Number> può essere assegnato a un ArrayList<? extends Number> o a un ArrayList<? extends Object> o a un ArrayList<? super Integer>
Perché ArrayList<Number> è un sottotipo dei 3 tipi citati sopra.
ArrayList<? extends Integer> può essere assegnato a un ArrayList<? extends Number> o a un ArrayList<? extends Object> o a un ArrayList<?>
Questo non vuol dire che puoi fare:
ArrayList<? extends Number> arr = new ArrayList<? extends Integer>(); // NOOOO (spiegato all'inizio)
Vuol dire che puoi fare ad esempio:
ArrayList<? extends Integer> arr = new ArrayList<Integer>();
ArrayList<? extends Number> arr2 = arr;
Andrea, andbin.dev – Senior Java developer – SCJP 5 (91%) • SCWCD 5 (94%)
java.util.function Interfaces Cheat Sheet — Java Versions Cheat Sheet