Preparare la certificazione Java Programmer OCPJP7: Generics

GENERICS

  • Quando si utilizzano i Generics come parametri, il tipo utilizzato DEVE essere esattamente lo stesso nella dichiarazione e nell’inizializzazione, altrimenti si ottiene un errore di compilazione.
    • List<Integer> intList = new ArrayList<Integer>(); -> OK
    • List<Number> intList = new ArrayList<Integer>(); -> ERRORE o Il subtyping NON funziona per i parametri Generics
  • Per ovviare a questa limitazione però Java mette a disposizione i parametri WILDCARD.
  • Definendo, ad esempio, un parametro come List<?>” significa che esso può rappresentare una lista di qualsiasi tipo come List<Integer>, List<String>, ecc..
  • Utilizzando le wildcard non ho nessuna limitazione ai tipi reali che posso assegnare alla reference.
  • Esempio:
    List<?> numList = new ArrayList<Integer>(); 
    numList = new ArrayList<String>(); 
  • Se si vuole limitare l’assegnamento solo ad alcuni sottotipi di una classe si può utilizzare la wildcard bounded, tramite la keyword extends:
    • List<? extends Number> numList = new ArrayList<Integer>(); 
      numList = new ArrayList<String>(); // ERRORE DI COMPILAZIONE 
    • In questo caso sono ammesse SOLO liste di tipi che estendono Number
  • Allo stesso modo si può utilizzare la keyword super per limitare i tipi che possono essere utilizzati a quelli che sono sovra classi di un determinato tipo: o List<? super Integer> intList = new ArrayList<Integer>();
  • Non si possono dichiarare campi static di un tipo generic T. Si ottiene un errore di compilazione.
  • Non si possono avere classi Exception che utilizzano i Generics. Si ottiene un errore di compilazione.
  • Le keywords extends e super cambiano di significato quando applicate ai Generics. In questo caso extends X e super X COMPRENDONO anche X stesso.
  • Una classe dichiarata con i Generics può essere utilizzata senza gli argomenti generics. In questo caso è utilizzata come un tipo raw.
  • Esempio:
    class A { … }
    A a = new A(); -> raw type
    A<D, D> a = new A(); -> dichiarazione VALIDA (può essere utilizzata senza argomenti sul lato destro dell’assegnamento)
  • Attenzione a NON confondere i placeholder con le classi.
  • Nell’esempio precedente X e Y sono i placeholder per i tipi Generics e non le classi dei tipi reali da passare come argomenti. D, invece, è una classe che viene utilizzata per dichiarare il tipo generics e che verrà sostituita nei relativi placeholder.
  • Attenzione all’utlizzo della sintassi diamond <> perché può essere utilizzata solo quando il tipo generics può essere inferito dal compilatore, come ad esempio in una inizializzazione.
  • Quando il tipo NON può essere inferito, il compilatore lo sostituisce con Object e questo può creare problemi se l’oggetto viene poi utilizzato da un metodo che si aspettavo un tipo diverso:
    • List<Integer> l = new ArrayList<>(); -> Il tipo viene inferito
    • myMethod(new ArrayList<>()); -> il tipo NON può essere inferito e, se myMethod si aspetta una List di oggetti di tipo diverso da Object, ottengo un errore di compilazione.
    • Quando si definisce una classe con i generics, come ad esempio class Q<T> { … } :
    • NON si possono definire reference static di tipo T
    • NON si possono istanziare oggetti o array di tipo T con l’operatore new
  • I dettagli sui tipi forniti ai Generics vengono eliminati con la type-erasure una volta compilato il codice.
    • A runtime quindi un ArrayList<String> generics ed un ArrayList raw sono dello stesso tipo class
    • Esempio
      class TypeCheck {
         public static void main(String[] args) {
            Class c1 = new ArrayList<String>().getClass(); 
            Class c2 = ArrayList.class; 
            System.out.println(c1 == c2);
         } 
      } 
    • Questo estratto di codice compila e stampa il valore true
This entry was posted in $1$s. Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *