Utilizzo dei Generics

      Nessun commento su Utilizzo dei Generics

java-logo

Utilizzo dei Generics

L’utilizzo dei Generics aggiunge stabilità al codice rendendo gli errori rilevabili in fase di compilazione .
Iniziamo subito con un esempio pratico, creiamo una classe Box che opera su oggetti di qualsiasi tipo. La nostra classe ha bisogno solo di due metodi: aggiungi che ache aggiunge un oggetto e un metodo get che recupera l’oggetto:

public class Box {

private Object object;

}

public void aggiungi(Object object) {

this.object = object;

}

public Object get() {

return object;

}

Dal momento che i metodi accettano o restituiscono oggetti di tipo Object, siamo liberi di passare qualsiasi tipo vogliamo, a condizione che non sia un tipo primitivo.Tuttavia, se è necessario limitare il tipo di contenuto a qualcosa di specifico (come Integer), l’unica opzione sarebbe quella di specificarlo ad esempio con un commento:

public class BoxDemo1 {

public static void main(String[] args) {

Box integerBox = new Box();

// utilizzare solo oggetti di tipo Integer nel box Box integerBox = new Box();

integerBox.aggiungi(new Integer(10));

Integer someInteger = (Integer)integerBox.get();

System.out.println(someInteger);

}

}

Il programma BoxDemo1 crea un oggetto di tipo Integer, poi passa questo al metodo aggiungi(), quindi assegna l’oggetto a someInteger utilizzando il metodo get(). Infine stampa il valore dell’oggetto (in questo caso 10) in output.Sappiamo che il cast da Object a Integer è corretto perché abbiamo rispettato quanto suggerito nel commento, ma cosa succederebbe se passassimo una stringa?

public class BoxDemo2 {

public static void main(String[] args) {

//utilizzare solo oggetti di tipo Integer nel box Box integerBox = new Box();

// Ora l’oggetto è di tipo String

integerBox.add(“10”);

// questo potrebbe essere scritto da un’altro // programmatore, notare i tipo Integer

Integer someInteger = (Integer)integerBox.get();

System.out.println(someInteger);}}

In questo secondo esempio abbiamo memorizzato il numero 10 come una stringa, tuttavia, il cast da Object a Integer è stato erroneamente trascurato. Questo è chiaramente un bug, ma poiché il codice viene compilato, non si sa nulla di questo bug, fino al runtime, cioè quando l’applicazione si blocca con una Eccezione .Se la classe Box fosse stata progettata con Generics, questo bug sarebbe stato catturato dal compilatore, invece di palesarsi in fase di runtime. Modifichiamo la classe Box utilizzando i Generics nel seguente modo public class Box<T>   in questo modo inseriamo una variabile T che può essere usata ovunque all’interno della classe.

public class Box<T> {

// T sta per “Tipo”

private T t;

public void aggiungi(T t) {

this.t = t;

}

public T get() {

return t;

}

}

Per fare riferimento a questa classe generica, dall’interno del codice, è necessario eseguire una chiamata di tipo generico, che sostituisce T con un valore concreto, come ad esempio Integer:

Box<Integer> integerBox;

Per creare un’istanza diquesta classe, si utilizzala parola chiave new, come al solito, ed <Integer> tra il nome della classe e la parentesi:

integerBox = new Box<Integer>();

Oppure

Box<Integer> integerBox = new Box<Integer>();

Una volta cheintegerBoxviene inizializzata, siamoliberi di invocare il metodo get() senza fornire un cast, come nel seguente esempio:

public class BoxDemo3 {

public static void main(String[] args) {

Box<Integer> integerBox = new Box<Integer>();

integerBox.aggiungi(new Integer(10));

Integer someInteger = integerBox.get();

System.out.println(someInteger);

}

}

Inoltre, se si tenta di aggiungere un tipo incompatibile con Box, come ad esempio un tipo String, la compilazione fallisce.

Metodi e Costruttori Generici

E’ possibile creare metodi e costruttori generici ovviamente l’utilizzo del parametro T è limitato all’interno del metodo o del costruttore:

public class Box<T> {

private T t;

public void aggiungi(T t) {

this.t = t;

}

public T get() {

return t;

}

public <U> void controllo(U u){
System.out.println(“T: ” + t.getClass().getName()); System.out.println(“U: ” + u.getClass().getName());

}

public static void main(String[] args) {

Box<Integer> integerBox = new Box<Integer>(); integerBox.aggiungi(new Integer(10)); integerBox. controllo(“testo”);

}

}

Abbiamo aggiunto un metodo generico, denominato controllo, che definisce un parametro di tipo U.

Questo metodo accetta un oggetto e lo stampa sullo standard output; stampa anche il tipo di T.

Per comodità, questa classe ha anche un metodo main così che possa essere eseguita come un’applicazione. L’output è:

T: java.lang.Integer

U: java.lang.String