Tipici generici

  • Sono un modello di programmazione che permette di definire, con una sola dichiarazione, un intero insieme di metodi o di classi
  • E’ un meccanismo molto potente
  • Da usare con consapevolezza

Ex.

public class Valore<T> //definisce un tipo generico della classe
{
	private final T val; //usa il tipo generuci della classe
	public Valore(T val) {this.val = val;}//usa il tipo generuci della classe
	public T get() {return val;}//usa il tipo generuci della classe
 
	@Override
	public String toString(){return "" + val;}
	public String toType(){return val.getClass().getName();}
}
  • Per definire un tipo generico della classe, si utilizza la sintassi a parentesi angolari dopo il nome della classe con il tipo generico da utilizzare
  • Da quel punto, si utilizza il tipo generico come un qualsiasi altro tipo di classe

Istanziare la classe generica

public static void main (String[] args)
{
	Valore <Integer> i = new Valore <> (42);
	Valore <String> s = new Valore <> ("ciao");
	Valore <Valore<String>> v = new Valore <> (s);
 
	System.out.println(i.get() + ":" + i.getType());
	System.out.println(s.get() + ":" + s.getType());
	System.out.println(v.get() + ":" + v.getType());
}

L’output sarà:

42: java.lang.Integer
ciao: java.lang.String
ciao: Valore

Classe Grafo

  • Il tipo del vertice può essere qualsiasi
  • Utilizzare Object fa perdere ogni informazione sul tipo del vertice e costringerebbe a continui downcast
public class Grafo <V>
{
	private Set <V> vertici;
 
	public void addVertex (V v) {/*...*/}
	public void getVertex (String id)
	{
		for (V v :vertici)
			if (V.toString().equals(id)) return v;
		return null;
	}
}

Coppia di elementi di tipo generico

public class Coppia <T>
{
	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;}
}

Specificare più tipi generici di classe

public class Coppia <T>
{
	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;}
}
  • Per convenzione i tipi generici sono chiamati con le lettere T, S, ecc. (E nel caso in cui siano elementi di una collection)

I generici funzionano solo con i tipi derivati

Warning

Non è possibile utilizzare tipi primitivi, ad es. int, double, char, ecc.

Estendere le classi generiche

  • Ovviamente è possibile estendere le classi generiche per creare classi più specifiche
  • Ad esempio, una classe Orario può estendere la classe Coppia:
public class Orario extends Coppia <Integer, Integer>
{
	public Orario (Integer a, Integer b)
	{
		super (a, b);
	}
}

Le interfacce Comparable e Comparator sono generiche

public interface Comparable <T>
{
	int compareTo (T o);
}
 
public interface Comparator <T>
{
	int compare (T o1, T o2);
}

Ex. Estendere un’interfaccia generica con vincolo di compatibilità sul tipo generico

public interface MinMAx <T extends Comparable<T>>
{
	T min();
	T max ();
}
 
public class MyClass <T extends Comparable <T>> implements MinMAx<T>
{
	//...
}

Definire un metodo generico

  • Per definire un metodo generico con il proprio tipo generico è necessario anteporre il tipo generico tra parentesi angolari al tipo di ritono:
static public <T> void esamina(ArrayList <T> lista)
{
	for (T o: lista)
		System.out.printlm(o.toString());
}

Usare <?> per prendere in input un oggetto di una classe con qualsiasi tipo parametrico

  • Nel caso in cui non sia necessario conoscere il tipo parametrico, si può utilizzare <?>
public class Punto <T extends Number>
{
	private T x;
	private T y;
 
	public Punto (T x, T y) {this.x = x; this.y = y;}
 
	@Override
	public String toString() {return "("+x+";"+y+")";}
 
	public static void main (String[] args)
	{
		Punto <?> p =  new Punto <Integer> (10, 42);
		System.out.println(p);
 
		p = new Punto <Double> (11.0, 43.5);
		System.out.println(p);
	}
}