Menu
Coddy logo textTech

Introduzione ai tipi generici

Fa parte della sezione Programmazione orientata agli oggetti del percorso Java di Coddy. Lezione 53 di 87.

Immagina di dover creare una classe che memorizza un valore e lo recupera in seguito. Senza i generics, dovresti scrivere classi separate per ogni tipo: una per Integer, una per String, una per Double e così via. Questo porta alla duplicazione del codice e a difficoltà di manutenzione.

I generics risolvono questo problema consentendoti di scrivere classi e metodi che funzionano con qualsiasi tipo, mantenendo al contempo la sicurezza dei tipi. Definisci un segnaposto (chiamato parametro di tipo) che viene sostituito con un tipo effettivo quando usi la classe:

// Senza generics - usa Object, richiede una conversione esplicita del tipo
List list = new ArrayList();
list.add("Hello");
String s = (String) list.get(0);  // È necessaria una conversione esplicita del tipo

// Con generics - tipi sicuri, nessuna conversione esplicita del tipo
List<String> list = new ArrayList<String>();
list.add("Hello");
String s = list.get(0);  // Non è necessaria una conversione esplicita del tipo

Le parentesi angolari <T> indicano un parametro di tipo. Quando scrivi List<String>, stai dicendo al compilatore che questa lista conterrà solo stringhe. Se provi ad aggiungere un intero, il compilatore rileva subito l’errore invece di fallire durante l’esecuzione.

I generics offrono due vantaggi fondamentali: eliminano la necessità di conversioni esplicite e rilevano gli errori di tipo in fase di compilazione invece che in fase di esecuzione. Questo rende il tuo codice più sicuro e pulito. Nelle lezioni successive vedremo come creare le tue classi e i tuoi metodi generici.

challenge icon

Sfida

Facile

Costruiamo un semplice sistema di archiviazione che dimostri la potenza dei generics confrontando il vecchio metodo (usando Object con il casting) con quello nuovo (usando i generics con sicurezza dei tipi).

Creerai tre file per vedere la differenza con i tuoi occhi:

  • OldBox.java: crea una classe che archivia valori con il metodo precedente ai generics. La tua OldBox dovrebbe avere un campo privato content di tipo Object. Includi un costruttore che accetti un Object e lo archivi, e un metodo getContent() che restituisca l'Object. Questo approccio funziona, ma richiede il casting quando recuperi i valori.
  • GenericBox.java: ora crea la versione moderna e sicura rispetto ai tipi, usando i generics. La tua GenericBox dovrebbe usare un parametro di tipo T nella dichiarazione. Deve avere un campo privato content di tipo T, un costruttore che accetti un valore T e un metodo getContent() che restituisca il tipo T. Non serve alcun casting quando usi questa classe!
  • Main.java: mostra entrambi gli approcci affiancati. Riceverai due input: una parola (String) e un numero (intero).

    Per prima cosa, usa il vecchio approccio: crea un OldBox che contenga la parola, poi recuperala con un cast a String e stampa: OldBox (with cast): [value]

    Successivamente, usa l'approccio generico: crea un GenericBox<String> che contenga la stessa parola, recuperala senza casting e stampa: GenericBox (no cast): [value]

    Poi mostra i generics in azione con gli interi: crea un GenericBox<Integer> che contenga il numero, recuperalo e stampa: GenericBox Integer: [value]

    Infine, stampa una riga vuota seguita da: Type safety: Generics catch errors at compile time!

Riceverai due input nell'ordine seguente: una parola (String) e un numero (intero come String, che dovrai analizzare).

Nota la differenza fondamentale: con OldBox, devi eseguire il cast (String) box.getContent() e sperare di aver ottenuto il tipo corretto. Con GenericBox, il compilatore conosce il tipo e non serve alcun casting. Questo è il vantaggio fondamentale dei generics: sicurezza dei tipi senza il fastidio del casting!

Provalo tu

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String word = scanner.nextLine();
        int number = Integer.parseInt(scanner.nextLine());
        
        // TODO: Crea un OldBox che contenga la parola
        // Recupera il valore con un cast a String e stampa: "OldBox (with cast): [value]"
        
        // TODO: Crea un GenericBox<String> che contenga la parola
        // Recupera il valore senza cast e stampa: "GenericBox (no cast): [value]"
        
        // TODO: Crea un GenericBox<Integer> che contenga il numero
        // Recupera il valore e stampa: "GenericBox Integer: [value]"
        
        // TODO: Stampa una riga vuota, poi stampa:
        // "Type safety: Generics catch errors at compile time!"
    }
}
quiz iconMettiti alla prova

Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.

Tutte le lezioni di Programmazione orientata agli oggetti

Esercitati da solo: Compilatore Java online