java generics
TRANSCRIPT
Diapositiva 1
Java
Generics
Davide [email protected]
Le collezioni di oggetti
Java mette a disposizione classi per contenere oggetti
Liste,Vettori
HashTable
Set
Sino a Java 1.4 queste classi lavoravano solo con Object, a partire da Java 1.5 e' stato introdotta una nuova sintassi
Object e le collezioni
Object la superclasse implicita di qualunque oggetto
Object un tipo generico, dal momento che qualunque classe un Object
Grazie a questa propriet di Object, possibile creare oggetti di dimensione variabile come Vector
Difetti delle
collezioni di Object
Utilizzando queste classi ci si rende subito conto che
si ha la necessit di ricorrere al casting per recuperare gli oggetti presenti nel contenitore
non esiste nessun controllo sul tipo di oggetti che effettivamente vengono inseriti nel Vector; se per errore si inserisce in v un oggetto diverso da String, la cosa verr notata soltanto in fase di esecuzione
Vector v = new Vector();
v.add("Polly");
// necessario il cast
String s = (String)v.get(0);
Vector v = new Vector();
v.add("Polly");
// ClassCastException
Long l = (Long)v.get(0);
Generics
Polimorfismo Parametrico
Per risolvere i problemi citati in Java 1.5 stato introdotto il concetto di Generics
I Generics hanno una nuova sintassi
Il tipo della collezione si dichiara in fase di definizione dell'oggetto
Errori di assegnazioni a oggetti non corretti vengono segnalati in fase di compilazione anzich in fase di esecuzione
Generics
Un esempio
Vector v = new Vector();
v.add("Polly");
// Nessun cast necessario
String s = v.get(0);
// da errore di compilazione
Long l = v.get(0);
Vector v = new Vector();
v.add("Polly");
// necessario il cast
String s = (String)v.get(0);
Senza Generics
Con Generics
Sintassi /1
Definizione
La nuova sintassi prevede la forma Vector
La E tra parentesi angolari denota un Tipo Parametrico deciso dall'utilizzatore
Grazie alla nuova sintassi il controllo sui tipi viene effettuato dal compilatore
Vector v = new Vector();
v.add("Polly");
v.add(new Integer(10)); // da errore di compilazione
String s = v.get(0); // Nessun cast necessario
Long l = v.get(0); // da errore di compilazione
Sintassi /2
Metodi
La classe Vector ha dei metodi che devono lavorare con i generics ad esempio add()
I metodi vengono dichiarati utilizzando il meta tipo
boolean add(E o) // prende in ingresso un generic
E get(int index) // restituisce un generic
Il simbolo E verr sostituito automaticamente con il tipo dichiarato in fase di creazione
Vector v = new Vector();
v.add("Polly");
Generics
Non solo Vector
Vector solo un esempio, i generics possono essere usati ad esempio sugli oggetti java.util.Map
HashMap lavora con la coppia chiave, valore che vengono gestiti entrambi come generics
HashMap
HashMap map = new HashMap();
map.put(10, "dieci");
map.put(20, "venti");
String s = map.get(10);
Generics
e valori di ritorno
Gli Identificatori generics possono restituire come valore di ritorno una classe parametrica dello stesso tipo di quello dichiarato al costruttore.
Il "vecchio" iterator()
public Iterator iterator()
diventa
public Iterator iterator()
Questo permette di avere iterators che non necessitano di casting
Esempi di iterators
Iterator i = v.iterator();
while (i.hasNext()) {
String s = (String)i.next();
System.out.println(s);
}
Iterator i = v.iterator();
while (i.hasNext()) {
String s = i.next();
System.out.println(s);
}
Senza Generics
Con Generics
Generics definiti
dall'utente
I Generics non sono soltato utilizzate dal JDK
Possono essere usati per creare proprie classi
Vediamo in dettaglio come funziona
Classe parametrica
Linea 1: La classe viene dichiarata con due tipi generics
Gli attributi ed i metodi fanno riferimento al meta tipo
public class Coppia {
private K k;
private V v;
public Coppia(K k, V v) {
this.k = k;
this.v = v;
}
public K getKey(){return k; }
public V getValue(){return v;}
}
Utilizzo classe Coppia
Cane c = new Cane("Fido");
Coppia nome1;
nome1 = new Coppia(c.getNome(), c);
Anatra a = new Anatra("Paperino");
Coppia nome2;
nome2 = new Coppia(a.getNome(), a);
La classe Coppia rappresenta un oggetto con tue valori
Vengono creati due oggetti
Peculiarit dei generics /1
Tutte le istanze di una classe generica condividono la stessa classe di base, anche se vengono specializzate in modo differente.
Coppia nome1 = new Coppia(...);
Coppia nome2 new Coppia(...);
Ci si aspetta che le due classi siano diverse per tipo ma esse condividono la stessa classe base quindi il confronto
nome1.getClass() == nome2.getClass()
ritorna true
Peculiarit dei generics /2
Non possibile assegnare un'istanza di una classe parametrica ad un reference con tipo parametrico pi generico
Vector v1 = new Vector();Vector v2 = v1; // errore di compilazione
Domanda 1: Perch questo non consentito?
Domanda 2: E' un difetto oppure un vantaggio?
Type safety
sicurezza nell'assegnamento dei tipi
Se una simile operazione fosse consentita, si otterrebbero due reference di tipo parametrico diverso che puntano allo stesso Vector di String.
Potremmo inserire all'interno di tale vettore oggetti differenti da String usando il reference v2:
v2.add(new Object); // violazione della type safety
Collezioni di tipo sconosciuto
Abbiamo visto che se si desidera definire una Collection in grado di accettare qualunque tipo, non possiamo usare Vector
Essa denota una Collection in grado di accettare unicamente oggetti di tipo Object
Per risolvere quello problema possibile definire generics di tipo parametrico sconosciuto
Questo si fa utilizzando il carattere '?' (punto interrogativo)
Utilizzo /1
Il codice riportato di seguito
crea due vettori che contengono rispettivamente solo Cani e solo Anatre (ricordiamo che entrambi gli oggetti estendono la classe Animale)
chiama un metodo in grado di stampare oggetti di tipo Animale
Sappiamo, per quanto detto prima, che Vector accetta solo Animale e non sue classi derivate
Vector cani = new Vector();Vector anatre = new Vector();t.stampaAnimali(cani); // errore di compilazionet.stampaAnimali(anatre);// errore di compilazionepublic void stampaAnimali(Vector c) { ... }
Utilizzo /2
Upper bound
Il metodo stampaAnimali deve essere reso capace di gestire la gerarchia Animale
Si utilizza la tecnica upper bound che permette di ricevere elementi di tipo Animale e di tutte le sue sottoclassi
La sintassi utilizza il wildcard e la parola extends
public void stampaAnimali(Vector