|
La parola final Possiamo usare la parola chiave final per indicare che un metodo non può essere ridefinito nelle classi derivate. Ecco un esempio:
Un Pesce è un Animale, e come tutti gli oggetti di classe Animale può essere interrogato. Anche in questo caso, scegliamo di ridefinire il metodo interroga(). Ma i pesci sono muti, e il metodo stampa solo tre puntini di sospensione. Possiamo anche scrivere altre classi che derivano da Pesce. Ad esempio, un Branzino è un Pesce, e quindi un Animale. Ma tutte le sottoclassi di Pesce avranno una limitazione: il metodo interroga() di Pesce è stato dichiarato final, quindi non può essere ridefinito in una sottoclasse. Dal punto di vista del design, la cosa ha perfettamente senso: quando abbiamo scritto la classe Pesce abbiamo deciso che tutti i pesci sono muti, e non vogliamo che qualche sottoclasse trasgredisca a questa regola. Se la classe Branzino provasse a fornire una propria implementazione del metodo interroga(), il risultato sarebbe un errore di compilazione:
Se ci sono motivi di design particolari, possiamo anche dichiarare final un’intera clas
Ora, nessuna classe può ereditare da Uomo. Provateci e otterrete un errore di compilazione. Naturalmente, tutti i metodi di una classe final sono implicitamente final. Dato che i metodi final non possono essere sovrascritti, non si pone il problema che abbiamo visto prima: possiamo tranquillamente invocare questi metodi da un costruttore. Usare final per le costanti La parola chiave final può essere usata anche in altri modi, non meno importanti. Come abbiamo visto, final è utilizzata nella dichiarazione di un metodo o di una classe è una barriera al meccanismo di ereditarietà. Ma la stessa parola chiave assume un significato diverso quando viene usata nelle dichiarazioni di oggetti e primitive. In questo caso, final significa: “il valore di questa variabile che segue non può essere cambiato”. Ad esempio:
Spesso, i campi final sono anche static (ricordiamo che i membri static appartengono alla classe anziché agli oggetti). Quindi le costanti Java si dichiarano in genere con la sequenza final static. Un esempio è il campoMAX_BESTIE della nostra classe Zoo:
Ora possiamo referenziare questa costante in qualsiasi punto del codice che ha accesso alla classe Zoo. Ad esempio:
Se avessimo omesso la parola static, avremmo avuto una copia di MAX_BESTIE per ogni oggetto di classe Zoo. Ma questo campo è costante e viene inizializzato sempre con lo stesso valore, quindi questa duplicazione sarebbe stata inutile. Ecco invece un esempio di campo final ma non static:
In questo caso la costante viene inizializzata alla costruzione dell’oggetto con un valore noto solo a tempo di compilazione. Ciascun oggetto ha un campo costante di valore diverso. Conclusioni Il polimorfismo e l’ereditarietà sono caratteristiche potentissime dei linguaggi a oggetti. Se vogliamo usarle bene, però, dobbiamo conoscerle a fondo. In caso contrario rischiamo di applicarle in modo inutile, o (come nel caso della chiamata di un metodo polimorfico da un costruttore) forse anche dannoso. Il prossimo mese ci occuperemo ancora di ereditarietà e polimorfismo. In particolare, introdurremo l’importante concetto di “classe astratta”.
|