© M. Badella G. Malnati L. Tessitore, 2003-05 Ereditarietà e polimorfismo Programmazione ad Oggetti A.A. 2004-05 © M. Badella G. Malnati L. Tessitore, 2003-05 Argomenti della lezione I concetti principali Ereditarietà in Java La classe Object Classi astratte e interfacce Programmazione ad Oggetti 2 © M. Badella G. Malnati L. Tessitore, 2003-05 Riusare il software A volte si incontrano classi con funzionalità simili In quanto sottendono concetti semanticamente “vicini” Una mountain bike assomiglia ad una bicicletta tradizionale È possibile creare classi disgiunte replicando le porzione di stato/comportamento condivise L’approccio “Taglia&Incolla”, però, non è una strategia vincente Difficoltà di manutenzione correttiva e perfettiva Meglio “specializzare” codice funzionante Sostituendo il minimo necessario Programmazione ad Oggetti 3 © M. Badella G. Malnati L. Tessitore, 2003-05 Ereditarietà Meccanismo per definire una nuova classe (classe derivata) come specializzazione di un’altra (classe base) La classe base modella un concetto generico La classe derivata modella un concetto più specifico La classe derivata: Dispone di tutte le funzionalità (attributi e metodi) di quella base Può aggiungere funzionalità proprie Può ridefinirne il funzionamento di metodi esistenti (polimorfismo) Programmazione ad Oggetti 4 © M. Badella G. Malnati L. Tessitore, 2003-05 Esempio Bicicletta coppia rapportoPosteriore … pedala(coppia) cambiaRapporto(n) frena(intensità) … MountainBike rapportoAnteriore cambiaRapportoAnt(n) Programmazione ad Oggetti Tandem coppia2 pedala2(coppia) 5 © M. Badella G. Malnati L. Tessitore, 2003-05 Terminologia Classe base, superclasse Bicicletta MountainBike Tandem Classi derivate, sottoclassi Programmazione ad Oggetti 6 © M. Badella G. Malnati L. Tessitore, 2003-05 Astrazione Il processo di analisi e progettazione del software di solito procede per raffinamenti successivi Spesso capita che le similitudini tra classi non siano colte inizialmente In una fase successiva, si coglie l’esigenza/opportunità di introdurre un concetto più generico da cui derivare classi specifiche Processo di astrazione Si introduce la superclasse che “astrae” il concetto comune condiviso dalle diverse sottoclassi Le sottoclassi vengono “spogliate” delle funzionalità comuni che migrano nella superclasse Programmazione ad Oggetti 7 © M. Badella G. Malnati L. Tessitore, 2003-05 Veicolo double getVelocità() double getAccelerazione() … Bicicletta void pedala() Programmazione ad Oggetti Automobile void avvia() void spegni() 8 © M. Badella G. Malnati L. Tessitore, 2003-05 Tipi ed ereditarietà Ogni classe definisce un tipo: Un oggetto, istanza di una sotto-classe, è formalmente compatibile con il tipo della classe base Il contrario non è vero! Esempio Un’automobile è un veicolo Un veicolo non è (necessariamente) un’automobile La compatibilità diviene effettiva se I metodi ridefiniti nella sotto-classe rispettano la semantica della superclasse L’ereditarietà gode delle proprietà transitiva Un tandem è un veicolo (poiché è una bicicletta, che a sua volta è un veicolo) Programmazione ad Oggetti 9 © M. Badella G. Malnati L. Tessitore, 2003-05 Vantaggi dell’ereditarietà Evitare la duplicazione di codice Permettere il riuso di funzionalità Semplificare la costruzione di nuove classi Facilitare la manutenzione Garantire la consistenza delle interfacce Programmazione ad Oggetti 10 © M. Badella G. Malnati L. Tessitore, 2003-05 Ereditarietà in Java Si definisce una classe derivata attraverso la parola chiave “extends” Seguita dal nome della classe base Gli oggetti della classe derivata sono, a tutti gli effetti, estensioni della classe base Anche nella loro rappresentazione in memoria Programmazione ad Oggetti 11 © M. Badella G. Malnati L. Tessitore, 2003-05 Ereditarietà in Java Veicolo.java public class Veicolo { private double velocità; private double accelerazione; public double getVelocità() {…} public double getAccelerazione() {…} } public class Automobile Automobile.java extends Veicolo { private boolean avviata; public void avvia() {…} } Programmazione ad Oggetti 12 © M. Badella G. Malnati L. Tessitore, 2003-05 Ereditarietà in Java Automobile a= new Automobile(); Memoria velocità: 0.0 accelerazione: 0.0 a Programmazione ad Oggetti avviata: false 13 © M. Badella G. Malnati L. Tessitore, 2003-05 Meccanismi Costruzione di oggetti di classi derivate Accesso alle funzionalità della superclasse Ri-definizione di metodi Programmazione ad Oggetti 14 © M. Badella G. Malnati L. Tessitore, 2003-05 Costruzione Per realizzare un’istanza di una classe derivata, occorre – innanzi tutto – costruire l’oggetto base Di solito, provvede automaticamente il compilatore, invocando – come prima operazione di ogni costruttore della classe derivata – il costruttore anonimo della superclasse Si può effettuare in modo esplicito, attraverso il costrutto super(…) Eventuali ulteriori inizializzazioni possono essere effettuate solo successivamente Programmazione ad Oggetti 15 © M. Badella G. Malnati L. Tessitore, 2003-05 Esempio class Impiegato { String nome; double stipendio; Impiegato(String n) { nome = n; stipendio= 1500; class Funzionario extends Impiegato { } } Funzionario(String n) { super(n); stipendio = 2000; } } Programmazione ad Oggetti 16 © M. Badella G. Malnati L. Tessitore, 2003-05 Accedere alla superclasse L’oggetto derivato contiene tutti i componenti (attributi e metodi) dell’oggetto da cui deriva Ma i suoi metodi non possono operare direttamente su quelli definiti privati La restrizione può essere allentata: La super-classe può definire attributi e metodi con visibilità “protected” Questi sono visibili alle sottoclassi Programmazione ad Oggetti 17 © M. Badella G. Malnati L. Tessitore, 2003-05 Ridefinire i metodi Una sottoclasse può ridefinire metodi presenti nella superclasse A condizione che abbiano Lo stesso nome Gli stessi parametri (tipo, numero, ordine) Lo stesso tipo di ritorno (La stessa semantica!) Per le istanze della sottoclasse, il nuovo metodo nasconde l’originale Programmazione ad Oggetti 18 © M. Badella G. Malnati L. Tessitore, 2003-05 Ridefinire i metodi class Base { int m() { return 0; } } class Derivata extends Base { int m() { return 1; } } Base b= new Base(); System.out.println(b.m()); Derivata d= new Derivata(); System.out.println(d.m()); Programmazione ad Oggetti 19 © M. Badella G. Malnati L. Tessitore, 2003-05 Ridefinire i metodi A volte, una sottoclasse vuole “perfezionare” un metodo ereditato, non sostituirlo in toto Per invocare l’implementazione presente nella super-classe, si usa il costrutto super.<nomeMetodo> ( … ) class Base { int m() { return 0; } } Programmazione ad Oggetti class Derivata extends Base { int m() { return super.m()+ 1; } } 20 © M. Badella G. Malnati L. Tessitore, 2003-05 Compatibilità formale Un’istanza di una classe derivata è formalmente compatibile con il tipo della super-classe Base b = new Derivata( ); Il tipo della variabile “b” (Base) limita le operazioni che possono essere eseguite sull’oggetto contenuto Anche se questo ha una classe più specifica (Derivata), in grado di offrire un maggior numero di operazioni Altrimenti viene generato un errore di compilazione Programmazione ad Oggetti 21 © M. Badella G. Malnati L. Tessitore, 2003-05 Compatibilità formale C print() D print() reset() Programmazione ad Oggetti C v1= new C(); C v2= new D(); D v3= new D(); v1.print() v2.print() v2.reset() v3.reset() 22 © M. Badella G. Malnati L. Tessitore, 2003-05 Polimorfismo class Base { int m() { return 0; } } class Derivata extends Base { int m() { return 1; } } Base b= new Derivata(); System.out.println(b.m()); Programmazione ad Oggetti 23 © M. Badella G. Malnati L. Tessitore, 2003-05 Polimorfismo Java mantiene traccia della classe effettiva di un dato oggetto Seleziona sempre il metodo più specifico… …anche se la variabile che lo contiene appartiene ad una classe più generica! Una variabile generica può avere “molte forme” Contenere oggetti di sottoclassi differenti In caso di ridefinizione, il metodo chiamato dipende dal tipo effettivo dell’oggetto Programmazione ad Oggetti 24 © M. Badella G. Malnati L. Tessitore, 2003-05 Polimorfismo Per sfruttare questa tecnica: Si definiscono, nella super-classe, metodi con implementazione generica… …sostituiti, nelle sottoclassi, da implementazioni specifiche Si utilizzano variabili aventi come tipo quello della super-classe Meccanismo estremamente potente e versatile, alla base di molti “pattern” di programmazione Programmazione ad Oggetti 25 © M. Badella G. Malnati L. Tessitore, 2003-05 Esempio Forma area() perimetro() Cerchio Rettangolo area() perimetro() area() perimetro() Programmazione ad Oggetti Forma f1 = new Cerchio(); Forma f2 = new Rettangolo(); double d1,d2; d1=f1.area(); d2=f2.area(); 26 © M. Badella G. Malnati L. Tessitore, 2003-05 La classe java.lang.Object In Java: Gerarchia di ereditarietà semplice Ogni classe ha una sola super-classe Se non viene definita esplicitamente una super-classe, il compilatore usa la classe predefinita Object Object non ha super-classe! Programmazione ad Oggetti 27 © M. Badella G. Malnati L. Tessitore, 2003-05 Metodi di Object Object definisce un certo numero di metodi pubblici Qualunque oggetto di qualsiasi classe li eredita La loro implementazione base è spesso minimale La tecnica del polimorfismo permette di ridefinirli public boolean equals(Object o) Restituisce “vero” se l’oggetto confrontato è identico (ha lo stesso riferimento) a quello su cui viene invocato il metodo Per funzionare correttamente, ogni sottoclasse deve fornire la propria implementazione polimorfica Programmazione ad Oggetti 28 © M. Badella G. Malnati L. Tessitore, 2003-05 Metodi di Object public String toString() Restituisce una rappresentazione stampabile dell’oggetto L’implementazione base fornita indica il nome della classe seguita dal riferimento relativo all’oggetto (java.lang.Object@10878cd) public int hashCode() Restituisce un valore intero legato al contenuto dell’oggetto Se i dati nell’oggetto cambiano, deve restituire un valore differente Oggetti “uguali” devono restituire lo stesso valore, oggetti diversi possono restituire valori diversi Utilizzato per realizzare tabelle hash Programmazione ad Oggetti 29 © M. Badella G. Malnati L. Tessitore, 2003-05 Controllare l’ereditarietà In alcuni casi, si vuole impedire esplicitamente l’utilizzo della tecnica del polimorfismo Ad esempio, per motivi di sicurezza o per garantire il mantenimento di una data proprietà del sistema Si utilizza la parola chiave “final” Un metodo “final” non può essere ridefinito da una sottoclasse Una classe “final” non può avere sottoclassi Un attributo “final” non può essere modificato Non c’entra nulla con l’ereditarietà! Programmazione ad Oggetti 30 © M. Badella G. Malnati L. Tessitore, 2003-05 Controllare l’ereditarietà In altri casi si vuole obbligare l’utilizzo del polimorfismo Si introducono metodi privi di implementazione Facendoli precedere dalla parola chiave “abstract” Una classe che contiene metodi astratti Deve essere, a sua volta, dichiarata abstract Non può essere istanziata direttamente Occorre definire una sottoclasse che fornisca l’implementazione dei metodi mancanti Programmazione ad Oggetti 31 © M. Badella G. Malnati L. Tessitore, 2003-05 Classi astratte abstract class Base { abstract int m(); } class Derivata extends Base { int m() { return 1; } } Base b= new Derivata(); System.out.println(b.m()); Programmazione ad Oggetti 32 © M. Badella G. Malnati L. Tessitore, 2003-05 Interfacce Una classe astratta può contenere metodi non astratti A beneficio delle proprie sottoclassi In alcuni casi, si vogliono definire metodi astratti senza vincolare la gerarchia di ereditarietà delle classi che li implementeranno Si utilizzano le interfacce: Insiemi di metodi astratti e costanti (attributi static final) Pubblici per definizione Una classe può implementare un’interfaccia Fornendo il codice relativo a tutti i metodi dichiarati nell’interfaccia Programmazione ad Oggetti 33 © M. Badella G. Malnati L. Tessitore, 2003-05 Esempio public interface Comparable { public int compareTo(Object o); } public class Rettangolo extends Forma implements Comparable { public int compareTo(Object o) { //codice relativo… } //altri attributi e metodi… } Programmazione ad Oggetti 34 © M. Badella G. Malnati L. Tessitore, 2003-05 Interfacce e tipi Analogamente alle classi, ogni interfaccia definisce un tipo Un oggetto che implementa una data interfaccia ha come tipo anche il tipo dell’interfaccia Un oggetto può implementare molte interfacce Di conseguenza può avere molti tipi Si può verificare se un oggetto ha un dato tipo con l’operatore “instanceof” if (myObject instanceof Comparable) … Programmazione ad Oggetti 35 © M. Badella G. Malnati L. Tessitore, 2003-05 Interfacce vuote Alcune interfacce non hanno metodi Servono solo come “marcatori” o indicatori di tipo Indicano che gli oggetti delle classi che le implementano godono di qualche proprietà Programmazione ad Oggetti 36 © M. Badella G. Malnati L. Tessitore, 2003-05 Interfacce vuote public interface Clonable { //indica che è lecito usare, // sulle istanze di questa classe // il metodo Object.clone() } public class Rettangolo extends Forma implements Comparable , Clonable { public int compareTo(Object o) { //codice relativo… } //altri attributi e metodi… } Programmazione ad Oggetti 37