In questa lezione impari a
- comprendere il concetto di ereditarietà
- creare gerarchie di classi con extends
- usare la parola chiave super
- capire protected e la visibilità nelle sottoclassi
- override di metodi ereditati
Cos'è l'ereditarietà?
L'ereditarietà permette di creare una nuova classe basata su una classe esistente.
La nuova classe (chiamata sottoclasse o classe figlia) eredita attributi e metodi dalla classe esistente (chiamata superclasse o classe padre).
È come dire: "X è un tipo di Y" (es: un Cane è un tipo di Animale)
Gerarchia di classi
Immagina questa situazione:
Scenario: sistema di gestione veicoli. Vogliamo gestire diversi tipi di veicoli:
- Tutti i veicoli hanno: marca, modello, anno
- Le Auto hanno in più: numero porte
- Le Moto hanno in più: tipo di motore
- I Camion hanno in più: capacità di carico
Invece di ripetere marca, modello, anno in ogni classe, usiamo l'ereditarietà!
Esempio base: Veicolo e Auto
// SUPERCLASSE (classe padre)
public class Veicolo {
// Attributi comuni a tutti i veicoli
protected String marca;
protected String modello;
protected int anno;
// Costruttore
public Veicolo(String marca, String modello, int anno) {
this.marca = marca;
this.modello = modello;
this.anno = anno;
}
// Metodi comuni
public void mostraInfo() {
System.out.println("Marca: " + marca);
System.out.println("Modello: " + modello);
System.out.println("Anno: " + anno);
}
public void avvia() {
System.out.println("Il veicolo è stato avviato.");
}
}
// SOTTOCLASSE (classe figlia)
public class Auto extends Veicolo {
// Attributo specifico per Auto
private int numeroPorte;
// Costruttore
public Auto(String marca, String modello, int anno, int numeroPorte) {
super(marca, modello, anno); // Chiama costruttore della superclasse
this.numeroPorte = numeroPorte;
}
// Metodo specifico per Auto
public void apriPorta() {
System.out.println("Porta aperta!");
}
// Override del metodo della superclasse
@Override
public void mostraInfo() {
super.mostraInfo(); // Chiama metodo del padre
System.out.println("Numero porte: " + numeroPorte);
}
}
Usare l'ereditarietà
public class TestVeicoli {
public static void main(String[] args) {
// Creare un'Auto
Auto miaAuto = new Auto("Fiat", "500", 2020, 3);
System.out.println("=== Informazioni Auto ===");
miaAuto.mostraInfo(); // Metodo override
miaAuto.avvia(); // Metodo ereditato
miaAuto.apriPorta(); // Metodo specifico di Auto
System.out.println();
// Creare un Veicolo generico
Veicolo veicoloGenerico = new Veicolo("Honda", "CBR", 2021);
System.out.println("=== Informazioni Veicolo ===");
veicoloGenerico.mostraInfo();
veicoloGenerico.avvia();
// veicoloGenerico.apriPorta(); // ERRORE! Non esiste in Veicolo
}
}
=== Informazioni Auto ===
Marca: Fiat
Modello: 500
Anno: 2020
Numero porte: 3
Il veicolo è stato avviato.
Porta aperta!
=== Informazioni Veicolo ===
Marca: Honda
Modello: CBR
Anno: 2021
Il veicolo è stato avviato.
Parole chiave importanti
extends.
class Auto extends VeicoloIndica che Auto eredita da Veicolo. Auto "è un tipo di" Veicolo.
super.
super(parametri)- chiama il costruttore della superclasse
super.metodo()- chiama un metodo della superclasseIMPORTANTE:
super()deve essere la PRIMA istruzione nel costruttore!
protected. Un modificatore di accesso che permette l'accesso:
- Dalla classe stessa
- Dalle sottoclassi
- Da altre classi nello stesso package
È un "via di mezzo" tra private e public, usato spesso con l'ereditarietà.
Gerarchia completa
// SUPERCLASSE
public class Veicolo {
protected String marca;
protected String modello;
protected int anno;
protected double velocitaMassima;
public Veicolo(String marca, String modello, int anno, double velocitaMassima) {
this.marca = marca;
this.modello = modello;
this.anno = anno;
this.velocitaMassima = velocitaMassima;
}
public void mostraInfo() {
System.out.println("=== Informazioni Veicolo ===");
System.out.println("Marca: " + marca);
System.out.println("Modello: " + modello);
System.out.println("Anno: " + anno);
System.out.println("Velocità max: " + velocitaMassima + " km/h");
}
public void avvia() {
System.out.println(marca + " " + modello + " avviato!");
}
}
// SOTTOCLASSE 1: Auto
public class Auto extends Veicolo {
private int numeroPorte;
private String tipologia; // berlina, suv, city car, etc.
public Auto(String marca, String modello, int anno, double velocitaMassima,
int numeroPorte, String tipologia) {
super(marca, modello, anno, velocitaMassima);
this.numeroPorte = numeroPorte;
this.tipologia = tipologia;
}
@Override
public void mostraInfo() {
super.mostraInfo();
System.out.println("Numero porte: " + numeroPorte);
System.out.println("Tipologia: " + tipologia);
}
public void apriPortabagagli() {
System.out.println("Portabagagli aperto!");
}
}
// SOTTOCLASSE 2: Moto
public class Moto extends Veicolo {
private String tipoMotore;
private boolean hasBauletto;
public Moto(String marca, String modello, int anno, double velocitaMassima,
String tipoMotore, boolean hasBauletto) {
super(marca, modello, anno, velocitaMassima);
this.tipoMotore = tipoMotore;
this.hasBauletto = hasBauletto;
}
@Override
public void mostraInfo() {
super.mostraInfo();
System.out.println("Tipo motore: " + tipoMotore);
System.out.println("Bauletto: " + (hasBauletto ? "Sì" : "No"));
}
public void impennaRuota() {
System.out.println("Impennata! 🏍️");
}
}
// SOTTOCLASSE 3: Camion
public class Camion extends Veicolo {
private double capacitaCaricoTon;
private int numeroAssi;
public Camion(String marca, String modello, int anno, double velocitaMassima,
double capacitaCaricoTon, int numeroAssi) {
super(marca, modello, anno, velocitaMassima);
this.capacitaCaricoTon = capacitaCaricoTon;
this.numeroAssi = numeroAssi;
}
@Override
public void mostraInfo() {
super.mostraInfo();
System.out.println("Capacità carico: " + capacitaCaricoTon + " tonnellate");
System.out.println("Numero assi: " + numeroAssi);
}
public void carica(double tonnellate) {
if (tonnellate <= capacitaCaricoTon) {
System.out.println("Caricate " + tonnellate + " tonnellate.");
} else {
System.out.println("Carico troppo pesante!");
}
}
}
Test completo
public class TestGerarchiaVeicoli {
public static void main(String[] args) {
// Creare diversi veicoli
Auto auto = new Auto("Fiat", "Panda", 2022, 160, 5, "City Car");
Moto moto = new Moto("Ducati", "Monster", 2023, 240, "4 cilindri", true);
Camion camion = new Camion("Iveco", "Daily", 2021, 120, 3.5, 2);
// Auto
auto.mostraInfo();
auto.avvia();
auto.apriPortabagagli();
System.out.println();
// Moto
moto.mostraInfo();
moto.avvia();
moto.impennaRuota();
System.out.println();
// Camion
camion.mostraInfo();
camion.avvia();
camion.carica(3.0);
camion.carica(5.0);
}
}
=== Informazioni Veicolo ===
Marca: Fiat
Modello: Panda
Anno: 2022
Velocità max: 160.0 km/h
Numero porte: 5
Tipologia: City Car
Fiat Panda avviato!
Portabagagli aperto!
=== Informazioni Veicolo ===
Marca: Ducati
Modello: Monster
Anno: 2023
Velocità max: 240.0 km/h
Tipo motore: 4 cilindri
Bauletto: Sì
Ducati Monster avviato!
Impennata! 🏍️
=== Informazioni Veicolo ===
Marca: Iveco
Modello: Daily
Anno: 2021
Velocità max: 120.0 km/h
Capacità carico: 3.5 tonnellate
Numero assi: 2
Iveco Daily avviato!
Caricate 3.0 tonnellate.
Carico troppo pesante!
Esempio: persone e studenti
// Superclasse
public class Persona {
protected String nome;
protected String cognome;
protected int eta;
public Persona(String nome, String cognome, int eta) {
this.nome = nome;
this.cognome = cognome;
this.eta = eta;
}
public void presenta() {
System.out.println("Ciao, sono " + nome + " " + cognome);
}
public String getNomeCompleto() {
return nome + " " + cognome;
}
public int getEta() {
return eta;
}
}
// Sottoclasse
public class Studente extends Persona {
private String matricola;
private String corso;
private double mediaVoti;
public Studente(String nome, String cognome, int eta,
String matricola, String corso) {
super(nome, cognome, eta);
this.matricola = matricola;
this.corso = corso;
this.mediaVoti = 0.0;
}
public void aggiungiVoto(double voto) {
// Semplificato: in realtà dovresti calcolare la media vera
mediaVoti = (mediaVoti + voto) / 2;
}
@Override
public void presenta() {
super.presenta(); // Chiama presenta() di Persona
System.out.println("Sono uno studente di " + corso);
System.out.println("Matricola: " + matricola);
}
public boolean ePromosso() {
return mediaVoti >= 6.0;
}
public void mostraInfo() {
System.out.println("Studente: " + getNomeCompleto());
System.out.println("Età: " + getEta());
System.out.println("Corso: " + corso);
System.out.println("Media: " + mediaVoti);
}
}
// Altra sottoclasse
public class Docente extends Persona {
private String materia;
private int anniServizio;
public Docente(String nome, String cognome, int eta,
String materia, int anniServizio) {
super(nome, cognome, eta);
this.materia = materia;
this.anniServizio = anniServizio;
}
@Override
public void presenta() {
super.presenta();
System.out.println("Insegno " + materia);
System.out.println("Ho " + anniServizio + " anni di servizio");
}
public void faiLezione() {
System.out.println("Il prof. " + cognome + " sta facendo lezione di " + materia);
}
}
public class TestScuola {
public static void main(String[] args) {
Studente studente = new Studente("Mario", "Rossi", 17, "12345", "Informatica");
Docente docente = new Docente("Laura", "Bianchi", 45, "Matematica", 20);
studente.presenta();
studente.aggiungiVoto(8);
studente.aggiungiVoto(7);
studente.mostraInfo();
System.out.println("Promosso: " + studente.ePromosso());
System.out.println("\n---\n");
docente.presenta();
docente.faiLezione();
}
}
Ciao, sono Mario Rossi
Sono uno studente di Informatica
Matricola: 12345
Studente: Mario Rossi
Età: 17
Corso: Informatica
Media: 3.75
Promosso: false
---
Ciao, sono Laura Bianchi
Insegno Matematica
Ho 20 anni di servizio
Il prof. Bianchi sta facendo lezione di Matematica
Regole dell'ereditarietà
Attenzione: regole importanti.
- In Java una classe può ereditare da UNA SOLA classe (no ereditarietà multipla)
- Una classe può avere MOLTE sottoclassi
- L'ereditarietà è transitiva: se C eredita da B e B da A, allora C eredita anche da A
- I costruttori NON vengono ereditati
- I metodi private NON vengono ereditati
- Tutti gli oggetti ereditano da
Object(la classe radice di Java)
Override dei metodi
L'override permette a una sottoclasse di fornire una propria implementazione di un metodo ereditato.
Usa l'annotazione
@Overrideper chiarezza (opzionale ma consigliato).
public class Animale {
public void emettiVerso() {
System.out.println("L'animale emette un verso");
}
}
public class Cane extends Animale {
@Override
public void emettiVerso() {
System.out.println("Bau bau! 🐕");
}
}
public class Gatto extends Animale {
@Override
public void emettiVerso() {
System.out.println("Miao! 🐱");
}
}
public class Mucca extends Animale {
@Override
public void emettiVerso() {
System.out.println("Muuu! 🐄");
}
}
// Test
Animale a1 = new Cane();
Animale a2 = new Gatto();
Animale a3 = new Mucca();
a1.emettiVerso(); // Bau bau! 🐕
a2.emettiVerso(); // Miao! 🐱
a3.emettiVerso(); // Muuu! 🐄
Esercizi guidati
⭐⭐ Medio
Esercizio 1 – forme geometriche.
Obiettivo: Creare una gerarchia di forme geometriche.
Requisiti:
- Crea una superclasse
Formacon:- Attributo protected: colore
- Metodo: mostraInfo()
- Crea sottoclasse
Rettangolocon:- Attributi: base, altezza
- Metodo: calcolaArea()
- Override mostraInfo()
- Crea sottoclasse
Cerchiocon:- Attributo: raggio
- Metodo: calcolaArea()
- Override mostraInfo()
⭐⭐ Medio
Esercizio 2 – dipendenti azienda.
Obiettivo: Gestire diversi tipi di dipendenti.
Requisiti:
- Superclasse
Dipendente: nome, cognome, stipendioBase - Sottoclasse
Manager: aggiunge bonus - Sottoclasse
Operaio: aggiunge oreStraordinario - Metodo calcolaStipendio() diverso per ogni tipo
Esercizi da svolgere
⭐ Facile
Esercizio 3 – animali domestici.
Crea gerarchia Animale → Cane/Gatto con:
- Attributi comuni: nome, età
- Metodo emettiVerso() diverso per ogni animale
- Metodi specifici: abbaia(), miagola()
⭐⭐ Medio
Esercizio 4 – conti bancari.
Crea ContoBancario → ContoCorrente/ContoRisparmio:
- ContoCorrente: con fido
- ContoRisparmio: con tasso interesse
- Metodi preleva() diversi
⭐⭐⭐ Difficile
Esercizio 5 – sistema Biblioteca.
Crea ElementoBiblioteca → Libro/Rivista/DVD:
- Attributi comuni: titolo, anno
- Libro: autore, pagine
- Rivista: numero, mese
- DVD: durata, regista
- Metodo mostraDettagli() per tutti
Concetti chiave da ricordare
extendscrea una relazione "è un tipo di"super()chiama il costruttore del padre (prima istruzione!)super.metodo()chiama metodo del padreprotected= accessibile nelle sottoclassi@Override= ridefinisci metodo ereditato- Solo ereditarietà singola in Java
- Riusa il codice ed evita duplicazioni!