Le classi parametriche – Lezione 22 di Java Avanzato

Creare ed utilizzare una classe parametrica

Le classi parametriche sono state introdotte con JAVA 5 nel 2004 per dare la possibilità ai programmatori di scrivere codice che potesse essere riutilizzato per oggetti di diverso tipo in maniera semplice e sicura.

Data una classe Pair che rappresenta una coppia di oggetti, una sua versione parametrica potrebbe essere la seguente:

  class Pair<T> {
    private T p1, p2;

    public Pair(T p1, T p2){
      this.p1 = p1;
      this.p2 = p2;
    }

    public T getFirst() {
      return p1;
    }

    public T getSecond() {
      return p2;
    }

  }

Il parametro T rappresenta un generico parametro di tipo che al momento della creazione della classe può essere “sostituito” con qualsiasi oggetto. Supponiamo di voler creare un oggetto Pair con due stringhe:

  Pair<String> p = new Pair<String>("oggetto1", "oggetto2");

La creazione di un oggetto parametrico utilizza due parentesi angolari in cui bisogna scrivere la classe effettiva che andrà a sostituire la T. In automatico il compilatore fornirà una versione della classe Pair con tutti i valori di tipo String.
La classe Pair può essere riutilizzata con qualsiasi tipo non primitivo, ad esempio:

  Pair<Integer> p = new Pair<Integer>(1, 2);

Abbiamo definito un oggetto di tipo Pair con due valori interi.

Scroprire gli errori a tempo di compilazione

I vantaggi che le classi parametriche portano sono immensi, in particolare dichiarando ad ogni occorrenza il tipo di parametro il codice diventa più leggibile e gli errori verranno scoperti a tempo di compilazione e non più a runtime. Consentono di riutilizzare il codice ad oggetti in modo semplice e sicuro. Inoltre, consente di evitare i casting: senza l’uso dei parametri di tipo, non conoscendo il tipo effettivo degli oggetti contenuti nelle classi per i tipi di ritorno di getFirst e getSecond dovremmo restituire degli Object; costringendoci infine ad effettuare dei casting:

  String name1 = (String) p.getFirst();
  String name2 = (String) p.getSecond();

Con i parametri di tipo il tipo di ritorno T verrà sostituito in automatico dal compilatore, di conseguenza possiamo scrivere direttamente:

  String name1 = p.getFirst();
  String name2 = p.getSecond();

Non c’è limite all’utilizzo dei tipi parametrici, ad esempio:

  class Pair<T, U> {
    private T p1;
    private U p2;

    public Pair(T p1, U p2){
      this.p1 = p1;
      this.p2 = p2;
    }

    public T getFirst() {
      return p1;
    }

    public U getSecond() {
      return p2;
    }

  }

Che verrà istanziata nel seguente modo:

  Pair<String, Integer> p = new Pair<String, Integer>("oggetto1", 2);
  Pair<Integer, Integer> p = new Pair<Integer, Integer>(1, 2); // U e T sono uguali

Alcuni compilatori considerano ridondante specificare i tipi degli oggetti nelle secondo parentesi angolari, è possibile ometterli perché il compilatore li considerà uguali alla prima parte della dichiarazione:

  Pair<String, Integer> p = new Pair<>("oggetto1", 2);
  Pair<Integer, Integer> p = new Pair<>(1, 2); // U e T sono uguali

Scrivere metodi e costruttori parametrici

E’ possibile dichiarare anche dei singoli metodi parametrici, per far ciò bisogna dichiarare nelle parentesi angolari il tipo parametrico che verrà utilizzo nel metodo. Ad esempio, il metodo seguente prende in ingresso un array e ne restituisce il primo elemento:

  public class Test {
    public static <T> T getFirstElem(T[] array) {
      return array[1];
    }
  }

Come si può notare la classe non è parametrica (non ha parametri di tipo dopo il nome), ma ha un metodo parametrico. rappresenta la dichiarazione del parametro di tipo che verrà utilizzato nel metodo, T rappresenta l’utilizzo vero e proprio del parametro. La T dopo <T> rappresenta il tipo di ritorno della funzione. Anche i costruttori delle classi possono essere parametrici definendo dei parametri di tipo nella loro intestazione.

I parametri di tipo non sono accessibili in un contesto statico perché assumono valori differenti in base alle varie istanze. Inoltre, possono estendere delle classi noti come:

  public static <T extends Comparable> T metodo(...) { //...}

In questo caso il metodo sarà costretto ad implementare il metodo compareTo di Comparable. I parametri di tipo possono estendere più classi facendole seguire dalla & commerciale:

  public static <T extends Comparable & Serializable> T metodo(...) { //...}

Le convenzioni per i nomi delle variabili di tipo nelle classi parametriche sono le seguenti:

  • <E>, elementi di collezioni;
  • K,V (Key, value), elementi per tabelle;
  • T (U,S,…), qualsiasi tipo.
Indice Lezione PrecedenteLezione Successiva

Pubblicato in Guide, Java, Programmazione Taggato con: , , , , , , , , ,

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

*