Un tipo generico è una classe o interfaccia generica parametrizzata sui tipi. La seguente classe Box verrà modificata per dimostrare il concetto.
Una classe Box semplice
Inizia esaminando una classe Box non generica che opera su oggetti di qualsiasi tipo. Deve solo fornire due metodi: set, che aggiunge un oggetto alla scatola, e get, che lo recupera:
Poiché i suoi metodi accettano o restituiscono un oggetto, sei libero di passare quello che vuoi , a condizione che non sia uno dei tipi primitivi. Non c’è modo di verificare, in fase di compilazione, come viene utilizzata la classe. Una parte del codice può inserire un numero intero nella casella e aspettarsi di estrarre numeri interi da esso, mentre un’altra parte del codice potrebbe passare erroneamente in una stringa, causando un errore di runtime.
Una versione generica della classe Box
Una classe generica è definita con il seguente formato:
class name<T1, T2, ..., Tn> { /* ... */ }
Per aggiornare il Box class per utilizzare i generici, puoi creare una dichiarazione di tipo generico modificando il codice “public class Box” in “public class Box < T > “. Questo introduce la variabile di tipo, T, che può essere usata ovunque all’interno della classe.
Con questa modifica, la classe Box diventa:
Come puoi vedere, tutte le occorrenze di Object sono sostituita da T. Una variabile di tipo può essere qualsiasi tipo non primitivo specificato: qualsiasi tipo di classe, qualsiasi tipo di interfaccia, qualsiasi tipo di array o anche un’altra variabile di tipo.
Questa stessa tecnica può essere applicata per creare interfacce generiche.
Convenzioni di denominazione dei parametri di tipo
Per convenzione, i nomi dei parametri di tipo sono lettere maiuscole singole. Ciò è in netto contrasto con le convenzioni di denominazione delle variabili che già conosci, e per una buona ragione: senza questa convenzione, sarebbe difficile distinguere tra una variabile di tipo e un nome di classe o interfaccia ordinario.
I nomi dei parametri di tipo più comunemente usati sono:
- E – Element (ampiamente utilizzato da Java Collections Framework)
- K – Key
- N – Numero
- T – Tipo
- V – Valore
- S, U, V ecc. – 2 °, 3 °, 4 ° tipo
Vedrai questi nomi usati in tutta l’API Java SE e nel resto di questa lezione.
Invocare e creare istanze di un tipo generico
Per fare riferimento alla classe Box generica dall’interno del codice, è necessario eseguire una chiamata di tipo generico, che sostituisce T con un valore concreto, come Integer:
Box<Integer> integerBox;
Puoi pensare a una chiamata di tipo generico come simile a una chiamata a un metodo ordinario, ma invece di passare un argomento a am ethod, stai passando un argomento di tipo – Integer in questo caso – alla classe Box stessa.
Come ogni altra dichiarazione di variabile, questo codice non crea effettivamente un nuovo oggetto Box. Dichiara semplicemente che integerBox conterrà un riferimento a “Box of Integer”, che è il modo in cui viene letto Box < Integer >.
L’invocazione di un tipo generico è generalmente noto come tipo parametrizzato.
Per istanziare questa classe, utilizzare la nuova parola chiave, come al solito, ma inserire < Intero > tra il nome della classe e le parentesi:
Box<Integer> integerBox = new Box<Integer>();
The Diamond
In Java SE 7 e versioni successive, è possibile sostituire gli argomenti di tipo richiesti per invocare il costruttore di una classe generica con un set vuoto di argomenti di tipo (< >) fintanto che il compilatore può determinare, o dedurre, gli argomenti del tipo dal contesto. Questa coppia di parentesi angolari, < >, è chiamata in modo informale il diamante. Ad esempio, puoi creare un’istanza di Box < Integer > con la seguente istruzione:
Box<Integer> integerBox = new Box<>();
Per ulteriori informazioni sulla notazione a rombo e sull’inferenza del tipo, vedere Inferenza del tipo.
Parametri di tipo multiplo
Come accennato in precedenza, una classe generica può avere più parametri di tipo.Ad esempio, la classe generica OrderedPair, che implementa l’interfaccia generica Pair:
Le seguenti istruzioni creano due istanze della classe OrderedPair:
Il codice, new OrderedPair < String, Integer >, istanzia K come String e V come Integer. Pertanto, i tipi di parametro del costruttore di OrderedPair sono String e Integer, rispettivamente. A causa dell’autoboxing, è valido passare una String e un int alla classe.
Come menzionato in The Diamond, perché un Il compilatore Java può dedurre i tipi K e V dalla dichiarazione OrderedPair < String, Integer >, queste istruzioni possono essere abbreviate utilizzando la notazione a rombi:
OrderedPair<String, Integer> p1 = new OrderedPair<>("Even", 8);OrderedPair<String, String> p2 = new OrderedPair<>("hello", "world");
Per creare un’interfaccia generica, segui le stesse convenzioni della creazione di una classe generica.
Tipi parametrizzati
OrderedPair<String, Box<Integer>> p = new OrderedPair<>("primes", new Box<Integer>(...));