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 (anche se [[#Utilizzo_delle_type_variables|non sono supportati]] in alcuni punti). Il ''client'' passa come parametro i tipi esatti da utilizzare.
 
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&lt;java.lang.String></tt> identifica una ''collezione di stringhe'' e si chiama ''parametrized type''. I ''raw types'' e i ''parametrized types'' sono definiti nel capitolo 4 delle specifiche di linguaggio.<ref group="D">[http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#110257 Raw Types]</ref><ref group="D">[http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#4.5 Parametrized Types]</ref>
 
=== 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 che viene passato come argomento (il cui ''component type'' non è noto ala codice del metodo)priori. Prima dell'introduzione dei ''generics'', il metodo doveva accettare un parametro <tt>Object[]</tt> e avere tipo di ritorno <tt>Object</tt>. DopoCon i ''generics'', si può definire una ''type variable'' <tt>E</tt> ed usarla sia come ''component type'' dell'array, sia come tipo di ritorno del metodo.
 
<source lang="Java">
public <E> E unElementoACaso(E[]class array)Utilities {
public <E> E unElementoACaso(E[] elementi) {
int indice = ...; // genera l'indice casualmente, in base al numero degli elementi dell'array
return arrayelementi[indice];
}
// ... 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>