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 tipoLe 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.
Sfida
FacileCostruiamo 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 privatocontentdi tipoObject. Includi un costruttore che accetti un Object e lo archivi, e un metodogetContent()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 tipoTnella dichiarazione. Deve avere un campo privatocontentdi tipoT, un costruttore che accetti un valoreTe un metodogetContent()che restituisca il tipoT. 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!"
}
}
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
1Fondamenti della programmazione a oggetti
File esterniIntroduzione alla programmazione a oggettiClassi e oggettiLa parola chiave thisMetodiCampi (attributi)Metodo costruttoreSovraccarico dei costruttoriRipasso - Calcolatrice semplice4Ereditarietà
Ereditarietà di base (extends)La parola chiave superSovrascrittura dei metodi (@Override)Concatenamento dei costruttoriLa classe ObjectEreditarietà singola e multilivelloPerché non esiste l'ereditarietà multipla delle classiRiepilogo: gerarchia dei dipendenti7Metodi speciali e classe Object
Metodo toString()equals() e hashCode()Metodo clone()compareTo() e ComparableInterfaccia ComparatorRiepilogo - Ordinamento personalizzato2Modificatori di accesso e incapsulamento
Panoramica dei livelli di accessoMetodi getter e setterNascondimento delle informazioniLa parola chiave finalRiepilogo - Gestore di conti bancari5Polimorfismo
Nozioni di base sull'overloading dei metodiOverride dei metodi (a runtime)Upcasting e downcastingL'operatore instanceofClassi e metodi astrattiRiepilogo - Calcolatore di forme8Concetti avanzati di OOP
Composizione vs ereditarietàAggregazione vs composizioneClassi interne, annidate e anonimeEnum e metodi degli EnumRecord (Java 16+)Classi sealed (Java 17+)11Modelli di progettazione Parte 1
Introduzione ai modelli di progettazionePattern SingletonPattern FactoryPattern BuilderPattern ObserverPattern Strategy3Proprietà di classe e membri statici
Variabili di istanza e staticheMetodi staticiBlocchi staticiCostanti (static final)Riepilogo - Contatore e utility6Interfacce e classi astratte
Introduzione alle interfacceImplementazione delle interfacceImplementazione di più interfacceMetodi default e static nelle interfacceClassi astratte e interfacce a confrontoInterfacce funzionaliRiepilogo: sistema di pagamento9Tipi generici
Introduzione ai tipi genericiClassi genericheMetodi genericiParametri di tipo con limitiCaratteri jolly (?, extends, super)Riepilogo - Contenitore generico12Modelli di progettazione – Parte 2
Pattern CommandPattern AdapterPattern DecoratorPattern Template MethodPattern StatePattern CompositePattern IteratorEsercitati da solo: Compilatore Java online