Java/Generics: differenze tra le versioni
Contenuto cancellato Contenuto aggiunto
mNessun oggetto della modifica |
|||
Riga 4:
== Type variables ==
Può risultare molto utile (in alcuni casi necessario) che una stessa entità di programma sia scritta per lavorare con tipi distinti e '''non''' legati tra loro da vincoli di ereditarietà. L'esempio classico è quello di una classe che implementa una collezione, e il cui codice deve poter lavorare nello stesso identico modo con tipi completamente diversi e che non sono noti a priori.
Un modo semplice per ottenere ciò è scrivere del codice che lavori con la classe <tt>java.lang.Object</tt>, dato che essa è a capo della gerarchia di tutti i tipi riferimento. Lo svantaggio principale è che i ''client'' devono servirsi di un cast ogni volta, e ciò non solo allunga il codice, ma aumenta il rischio di bachi (ClassCastExceptions non desiderate) nel caso di errori di battitura nella scrittura dell'operatore di cast.
Riga 10:
Il linguaggio fornisce una alternativa, che consiste nell'uso di una ''type variable'', ovvero un identificatore che rappresenta un tipo che non è noto a priori. Le ''type variables'' sono definite nel capitolo 4 delle specifiche di linguaggio.<ref group="D">[http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#108850 The Java Language Specification, Chapter 4]</ref>
L'idea di fondo è che il codice generico definisca nell'interfaccia uno o più ''type parameters'', i quali assumono il ruolo di ''type variables'' nell'implementazione, comportandosi esattamente come tipi riferimento noti
Una ''type variable'' può essere definita a livello di classe, di interfaccia, di metodo o di costruttore.
Riga 30:
</source>
In questo caso, <tt>Collezione</tt> è un tipo generico, ed <tt>E</tt> è il nome dell'unico ''type parameter''. La scrittura <tt>Collezione</tt> è chiamata ''raw type''; la scrittura <tt>Collezione<java.lang.String></tt> identifica una ''collezione di stringhe'' e si chiama ''parametrized type''
=== Istanziazione ===
Al momento di istanziare una ''classe concreta generica'', è necessario indicare il tipo effettivo da sostituire al parametro. Si può istanziare secondo queste due modalità:
*lasciando che il compilatore attribuisca il tipo in automatico, oppure
*esplicitando il tipo.
Il primo caso consiste nell'indicare una coppia di parentesi angolate vuota (chiamata ''diamond operator''):
ArrayList<String> listaDiStringhe = new ArrayList<>();
Il secondo caso consiste nell'indicare i tipi effettivi tra parentesi angolate; può essere usato per rendere il codice più chiaro, ed è richiesto dal compilatore in caso di ambiguità:
new ArrayList<String>();
=== Uso dei raw types ===
Line 38 ⟶ 49:
Anche i metodi e i costruttori possono definire uno o più ''type parameters''.
Ad esempio, si consideri un metodo che estrae un elemento a caso da un array
<source lang="Java">
public <E> E unElementoACaso(E[] elementi) {
int indice = ...; // genera l'indice casualmente, in base al numero degli elementi dell'array
return
}
// ... altri metodi
}
</source>
In questo esempio, il metodo
<source lang="Java">
public E unElementoACaso(E[] array)
</source>
è stato scritto in base al ''type parameter'' <tt>E</tt>. Una sintassi analoga vale per i costruttori.
=== Invocazione ===
I ''client'' che invocano il metodo indicano il tipo effettivo da sostituire al parametro. Possono invocare il metodo secondo queste due modalità:
*lasciando che il compilatore attribuisca il tipo in automatico, oppure
*esplicitando il tipo.
Il primo caso è quello utilizzato più di frequente, e consiste nell'usare la stessa sintassi che invoca un metodo non generico. Ad esempio:
<source lang="Java">
public void stampaRecordACaso(Record[] records) {
Utilities utilities = new Utilities();
Record r = utilities.unElementoACaso(records);
stampaRecord(r);
}
</source>
Il secondo caso può essere usato per rendere il codice più chiaro, e a volte è richiesto dal compilatore in caso di ambiguità.
<source lang="Java">
public void stampaRecordACaso(Record[] records) {
Utilities utilities = new Utilities();
Record r = utilities.<Record> unElementoACaso(records);
stampaRecord(r);
}
</source>
|