Scarica Dynamic binding e polimorfismo in Java e più Schemi e mappe concettuali in PDF di Programmazione Java solo su Docsity!
Programmazione ad Oggetti in Java
Dynamic Binding e Polimorfismo
Questa dispensa tratta due dei concetti più importanti della programmazione orientata agli oggetti:
il Polimorfismo , che permette a un oggetto di assumere forme diverse, e il Dynamic Binding , il
meccanismo con cui Java sceglie a runtime quale implementazione di un metodo eseguire. Viene
inoltre illustrata la Superclasse Universale Object e i suoi metodi fondamentali.
Argomenti trattati
1. Polimorfismo
2. Upcast e Downcast
3. L'operatore instanceof
4. Dynamic Binding
5. Metodi final e classi final
6. Limiti del Dynamic Binding
7. La Superclasse Universale Object
8. I metodi equals e toString
1. Polimorfismo
Il Polimorfismo , insieme all'ereditarietà, è uno dei concetti fondamentali della programmazione
orientata agli oggetti. Il termine deriva dal greco e significa molte forme : indica la capacità di un
oggetto di appartenere a diversi tipi e quindi di assumere più forme.
1.1 Esempio con gerarchia di classi
Consideriamo una gerarchia di tre classi: Studente come classe base, Laureato e NonLaureato
come classi derivate.
Studente
Laureato NonLaureato
Grazie al polimorfismo, una variabile di tipo Studente può riferirsi a oggetti di tipo Laureato o
NonLaureato , perché entrambe sono sottoclassi di Studente. Questo funziona in due modi
equivalenti:
// Modo 1: assegnazione separata Studente s = new Studente(); Laureato l = new Laureato(); NonLaureato nl = new NonLaureato();
s = l; // s ora punta a un oggetto Laureato s = nl; // s ora punta a un oggetto NonLaureato
// Modo 2: istanziazione diretta Studente s = new Laureato(); s = new NonLaureato();
Regola fondamentale: a una variabile il cui tipo è una classe antenato si può assegnare
qualsiasi oggetto di una classe discendente. Il contrario non è possibile senza conversione
esplicita.
1.2 Polimorfismo nei parametri di metodo
Il polimorfismo torna utile anche nella firma dei metodi. Se un metodo accetta un parametro di tipo
Studente , è possibile passargli qualsiasi oggetto di una classe che estende Studente, senza
alcuna conversione.
oggetto instanceof NomeClasse
// Restituisce true se oggetto e' un'istanza di NomeClasse // (o di una sua sottoclasse) // Restituisce false altrimenti
3.1 Esempio: downcast sicuro
Persona p = new Persona(); Studente s = new Studente();
// Downcast NON sicuro (p non e' uno Studente): instanceof ritorna false if (p instanceof Studente) { s = (Studente) p; // blocco non eseguito }
// Downcast sicuro (s e' anche Persona): instanceof ritorna true if (s instanceof Persona) { p = (Persona) s; // perfettamente valido }
4. Dynamic Binding
Il Dynamic Binding (o late binding ) nasce direttamente dal polimorfismo. Quando si invoca un
metodo su un riferimento polimorfo, Java non sceglie quale implementazione eseguire in fase di
compilazione (in base al tipo dichiarato della variabile), ma lo decide a runtime , in base al tipo
effettivo dell'oggetto a cui il riferimento punta.
4.1 Esempio pratico
Consideriamo le classi Persona e Studente , dove Studente ridefinisce ( override ) il metodo
stampaInfo():
public class Persona { private String nome; private String cognome;
public Persona(String nome, String cognome) { this.nome = nome; this.cognome = cognome; }
public void stampaInfo() { System.out.println("Nome: " + nome + " Cognome: " + cognome); } }
public class Studente extends Persona { private int matricola;
public Studente(String nome, String cognome, int matricola) { super(nome, cognome); this.matricola = matricola; }
@Override public void stampaInfo() { super.stampaInfo(); System.out.println("Matricola: " + matricola); } }
Nel metodo main, osserviamo il Dynamic Binding in azione:
Metodi final Per definizione non possono essere ridefiniti.
Metodi statici Appartengono alla classe, non all'istanza: vengono
invocati con il nome della classe e non beneficiano del
binding dinamico.
7. La Superclasse Universale: Object
In Java ogni classe — anche quelle definite senza ereditarietà esplicita — è una sottoclasse della
classe Object. Se non si specifica alcuna superclasse, il compilatore aggiunge automaticamente
extends Object. Di conseguenza ogni oggetto di ogni classe è di tipo Object.
Questo significa che la gerarchia di qualsiasi sistema Java ha sempre Object alla radice. Per
esempio, con le classi A e B dove B estende A:
Object // radice universale nn A // estende Object implicitamente nn B // estende A (e quindi anche Object)
Grazie alla classe Object, in Java è possibile scrivere codice generico che opera su qualsiasi
tipo di oggetto — per esempio le strutture dati della Java Collections Framework.
8. I metodi equals e toString
La classe Object fornisce alcuni metodi che ogni classe Java eredita. I più importanti sono equals
e toString. Poiché la loro implementazione predefinita è molto generica, è buona pratica ridefinirli
( override ) in ogni classe.
8.1 Il metodo equals
Il metodo equals serve a confrontare due oggetti per uguaglianza logica. La versione ereditata da
Object confronta i riferimenti in memoria (uguaglianza fisica), non il contenuto degli oggetti.
Firma nella classe Object:
public boolean equals(Object altroOggetto) { ... }
Attenzione: se si definisce un metodo con parametro di tipo diverso da Object, non si tratta di un
override ma di un overloading. Per fare correttamente l'override è necessario accettare un
parametro di tipo Object e poi usare instanceof per verificare il tipo effettivo.
Esempio di override corretto nella classe Persona:
@Override public boolean equals(Object altroOggetto) { if (altroOggetto == null) return false; if (altroOggetto instanceof Persona) { Persona p = (Persona) altroOggetto; return nome.equals(p.nome) && cognome.equals(p.cognome); } return false; }
Riepilogo
Concetto Definizione sintetica
Polimorfismo Un oggetto di una classe derivata può essere trattato come
un oggetto della classe base.
Upcast Assegnazione da tipo derivato a tipo base. Sempre sicuro,
senza casting esplicito.
Downcast Assegnazione da tipo base a tipo derivato. Richiede casting
esplicito; può fallire a runtime.
instanceof Operatore per verificare il tipo effettivo di un oggetto prima di
un downcast.
Dynamic Binding A runtime Java esegue l'implementazione del metodo del
tipo effettivo dell'oggetto, non del tipo dichiarato.
final Impedisce l'override di un metodo o l'estensione di una
classe.
Object Superclasse universale di tutte le classi Java.
equals Metodo di Object per il confronto logico tra oggetti; va
ridefinito.
toString Metodo di Object per la rappresentazione testuale; va
ridefinito.
Dynamic Binding e Polimorfismo sono le due facce di una stessa medaglia: proprio perché
esiste il polimorfismo si ha l'effetto del dynamic binding.