Permettono di definire con una classe un insieme di classi su tipi diversi utilizzati all’interno della stessa: e’ un meccanismo molto potente con molti meccanismi sottili, alcuni da conoscere.

Tutte le collezioni che abbiamo visto ed utilizzato, sfruttano i Generics (parentesi triangolari).
Per creare un’istanza di classi con Generici, semplicemente creiamo un’istanza di una classe passando uno o più tipi fra parentesi angolari:

new ArrayList();

Per assegnare le variabili di tipi generici:

List listaDiStringhe = new ArrayList();

Possiamo anche prendere input di tipi generici:

public void metodo (Lis lista)
{
    //...
}

Definire una classe Generica

Specifichiamo il nome della classe con affianco uno o più tipi separati da virgola.

public class Coppia 
{
    private T a,b;
    public Coppia(T a, T b)
    {
        this.a = a;
        this.b = b;
    }
    public T getPrimo()
    { 
        return a;
    }
    public T getSecondo()
    {
        return b;
    }
}

Per utilizzarla invece:

Coppia c1 = new Coppia (10, 20);
Coppia c2 = new Coppia (10.5, 20.5);

Il controllo sulla corrispondenza fra valore attuale e parametro del metodo viene fatto in compilazione.

Per specificare più tipi generici invece

public class Coppia
{
    private T a
    private S b;
    public Coppia(T a, S b)
    {
        this.a = a;
        this.b = b;
    }
    public T getPrimo()
    { 
        return a;
    }
public S getSecondo()
   { 
       return b;
   }
}

Estendere classi Generiche

Possiamo estendere le classi generiche in questo modo:

public class Orario extends Coppia
{
    public Orario(Integer a, Integer b)
    {
        super(a,b);
    }
}

O una classe Data:

public class Data extends Coppia >
{
    public Data(Integer giorno, Integer mese, Integer anno)
    {
        super(giorno, new Coppia(mese,anno);
    }
}

Esercizio: Lista Linkata generica

Non posso instanziare un tipo generico con un tipo primitivo: devo essere sicuro che almeno i metodi della classe object li possieda.

Alcuni esempi di interfaccie generiche:

public interface List
{
    void add(e,x);
    Iterator iterator();
}
public interface Iterator
{
    E next();
    boolean hashNext();
}

Principalmente i generics vengono utilizzate nelle collezioni (Collections).

Ad esempio, l’ intestazione della classe ArrayList:

public class ArrayList
extends AbstractList
implements List, RandomAccess, Cloneable, Serializable

Se devo definire solo un metodo con un tipo generico invece, posso fare così:

static public void esamina(ArrayList lista)
{
    for (T o : lista)
    {
        System.out.println(o.tostring());
    }
}