Scaricare la presentazione
La presentazione è in caricamento. Aspetta per favore
PubblicatoAmedea Fede Modificato 11 anni fa
1
Subtype Polymorphism
2
Interfacce e subtype polimorfismo Tipi, sottotipi e conversioni di tipo Polimorfismo e dinamic dispatch
3
Conversioni di tipo Variabile: locazione con un tipo associato Tipo della variabile determinato dal compilatore guardando la dichiarazione Una variabile di tipo reference contiene un riferimento ad un oggetto Oggetto: istanza di una classe Tipo delloggetto: la classe che lo crea Determinato a run time Una variabile può assumere come valori riferimenti ad oggetti di classi diverse Continua…
4
Conversioni di tipo È possibile assegnare un riferimento di tipo classe ad una variabile di tipo interfaccia purchè la classe implementi linterfaccia BankAccount account = new BankAccount(10000); Measurable x = account; // OK Coin dime = new Coin(0.1, "dime"); Measurable y = dime; // OK Continua…
5
Conversioni di tipo La conversione è lecita solo in determinate situazioni Problema: Rectangle non implementa Measurable Measurable x = new Rectangle(5, 10, 20, 30); // ERRORE
6
Subtyping Subtyping (<:) Una relazione che permette di decidere quando è legittimo convertire un tipo riferimento in un altro Chi decide cosa/quando è legittimo? il compilatore! Per il momento la regola è: Continua… T1 <: T2 sse T1 è una classe, T2 è una interfaccia T1 implementa T2.
7
Subtyping Principio di sostituibilità Un riferimento di un sottotipo può essere usato ovunque ci si aspetti un riferimento di un supertipo Le regole di sottotipo devono garantire la correttezza del principio di sostituibilità Continua…
8
Subtyping La regola C <: I se C implementa I Principio di sostituibilità un riferimento di tipo C può sempre essere usato dove si attende un riferimento di tipo I E ragionevole perché se C implementa I, C definisce public tutti i metodi dichiarati da I Quindi tutti le invocazioni di metodo possibili per I sono supportate da C Continua…
9
Subtyping e regole di typing Regola di assegnamento Un riferimento di tipo T1 si puo sempre assegnare ad una variabile di tipo T2 sse T1 <: T2 Un riferimento di tipo classe può sempre essere assegnato ad una variabile di tipo interfaccia (se la classe implementa linterfaccia) Regola di passaggio di parametri Un riferimento di tipo T1 si puo sempre passare per un parametro di tipo T2 sse T1 <: T2 Un riferimento di tipo classe può sempre essere passato per un parametro di tipo interfaccia (se la classe implementa linterfaccia)
10
Domanda Data limplementazione generica della classe DataSet, che oggetti possiamo passare come argomento per x ? public class DataSet { public void add(Measurable x) {... }... }
11
Risposta Qualunque istanza di una una classe che implementa Measurable
12
Polimorfismo – dynamic dispatch Una variabile di tipo interfaccia ha sempre come valore un riferimento di una classe che implementa linterfaccia Continua… Measurable x; x = new BankAccount(10000); x = new Coin(0.1, "dime");
13
Polimorfismo – dynamic dispatch Possiamo invocare ognuno dei metodi dellinterfaccia: Quale metodo invoca? double m = x.getMeasure();
14
Polimorfismo – dynamic dispatch Dipende dal riferimento corrente memorizzato nella variabile Se x riferisce un BankAccount, invoca il metodo BankAccount.getMeasure() Se x riferisce un Coin, invoca il metodo Coin.getMeasure() Polimorfismo (molte forme): il comportamento varia, e dipende dal tipo dinamico della variabile Continua…
15
Domande 5.È impossibile costruire un oggetto di tipo Measurable. Perché? 6.Perché invece é possibile dichiarare una variabile di tipo Measurable ?
16
Risposte 5. Measurable è una interfaccia. Le interfacce non hanno campi o implementazione di metodo. 6.Perché Measurable è un tipo: la variabile non riferirà mai una istanza di Measurable, (le interfacce non hanno istanze) ma piuttosto oggetto di una qualche classe che implementa linterfaccia Measurable. Continua…
17
Costruiamo una applicazione per disegnare un insieme di forme geometriche contenute in una componente grafico: definiamo GWin, una classe che descrive un contenitore di forme geometriche disegnate mediante una invocazione del metodo paint() per esemplificare, consideriamo due tipi di forme: Car e Smiley Ancora un esempio
18
Forme grafiche class Car {... public void draw(Graphics2D g) { // Istruzioni per il disegno... } } class Smiley {... public void draw(Graphics2D g) { // Istruzioni per il disegno... } }
19
Un contenitore di Cars e Smileys GWin /** Una finestra che contiene un insieme Cars e Smileys */ class GWin { /** Disegna tutte le forme di questo component */ public void paint(){ /* disegna su g */ } /** Componente grafica su cui disegnare */ private Graphics2D g; }
20
Domanda Che struttura utilizziamo per memorizzare le forme contenute nella GWin ? Come definiamo il metodo paint() in modo che disegni tutte le forme della componente?
21
Risposte definiamo una nuova interfaccia: Shape Ridefiniamo le classi Car e Smiley in modo che implementino Shape Memorizziamo gli oggetti della componente in una ArrayList interface Shape { void draw(Graphics2D g); }
22
Car e Smiley implementano Shape class Car implements Shape {... public void draw(Graphics2D g) { // Istruzioni per il disegno... } } class Smiley implements Shape {... public void draw(Graphics2D g) { // Istruzioni per il disegno... } }
23
Mantiene una ArrayList GWin class GWin { private Graphics2D g; private ArrayList shapes; // crea una GWin con un insieme di forme public GWin(Shape... shapes) { Graphics2D g = new Graphics2D(); this.shapes = new ArrayList (); for (Shape s:shapes) this.shapes.add(s); } // disegna tutte le componenti della GWin public void paint() { for (Shape s:shapes) s.draw(g); }
24
Diagramma delle Classi Car GWin Smiley Shape Car
25
So long, for today
26
Polimorfismo – dynamic dispatch Dynamic dispatch : Il metodo da invocare per rispondere ad un messaggio è deciso a tempo di esecuzione
27
Dynamic dispatch in GWin class GWin {... private ArrayList shapes;... public void paint() { // disegna tutte le componenti della GWin // il metodo invocato effettivamente da ogni // messaggio s.draw(g) dipende dalla classe // di cui s è istanza ed è deciso a runtime for (Shape s:shapes) s.draw(g); }.... }
28
Dynamic dispatch vs overloading Dynamic dispatch : Il metodo da invocare per rispondere ad un messaggio è deciso a tempo di esecuzione Notiamo bene Il metodo da invocare è deciso a runtime il compilatore decide se esiste un metodo da invocare Overloading: Nel caso esista più di un metodo, il compilatore decide staticamente il tipo del metodo da invocare
29
Dynamic dispatch vs overloading interface I { public String m(boolean b); public String m(double d); } class A implements I { public String m(boolean b) { return A.m(boolean); } public String m(double d) { return A.m(double); } } class B implements I { public String m(boolean b) { return B.m(boolean); } public String m(double d) { return B.m(double); } }
30
Dynamic dispatch vs overloading class Client { public void static show(I x) { // tipo del metodo invocato = m(boolean) // deciso dal compilatore staticamente // metodo invocato deciso dinamicamente // in funzione del tipo dellargomento // passato per x System.out.println( x.m(false) ); }
31
Domanda Che cosa hanno in comune i meccanismi di overloading e di dynamic dispatch? In cosa sono diversi?
32
Entrambi i meccanismi contribuiscono a decidono quale metodo eseguire in risposta ad un messaggio, ma Nelloverloading scelta è relativa al tipo del metodo, ed è fatta in compilazione guardando il tipo dei parametri Nel dynamic dispatch la scelta è relativa al corpo del metodo, ed è fatta in esecuzione guardando il tipo delloggetto che riceve il messaggio Risposta
33
Subtyping e sostituibilità Principio di sostituibilità Un riferimento di un sottotipo può essere usato ovunque ci si aspetti un riferimento di un supertipo Le regole di sottotipo garantiscono la correttezza del principio di sostituibilità Tutti i metodi del supertipo devono essere implementati dal sottotipo Il sottotipi può avere anche altri metodi Continua…
34
Subtyping e perdita di informazione Principio di sostituibilità Un riferimento di un sottotipo può essere usato ovunque ci si aspetti un riferimento di un supertipo Può causare perdita di informazione nel contesto in cui ci aspettiamo il supertipo, non possiamo usare solo I metodi del supertipo perdiamo la possibilità di utilizzare gli eventuali metodi aggiuntivi del sottotipo Continua…
35
Car e Smiley implementano Shape class Smiley implements Shape {... public void draw(Graphics2D g){... } public String mood() {... } } class Car implements Shape {... public void draw(Graphics2D g){... } public String brand() {... } }
36
Subtyping e perdita di informazione Consideriamo public static void printBrand(List l) { for (Shape s : l) // stampa la marca di tutte le macchine di l // ??? } Continua…
37
Subtyping e perdita di informazione Certamente non possiamo fare così … public static void printBrand(List l) { for (Shape s : l) // stampa la marca di tutte le macchine di l System.out.println( s.brand() ); // TYPE ERROR! } Continua…
38
Cast Permette di modificare il tipo associato ad una espressione Un cast è permesso dal compilatore solo se applica conversioni tra tipi compatibili Compatibili = sottotipi (per il momento) Anche quando permesso dal compilatore, un cast può causare errore a run time Se s non è un Car errore a run time Continua… ((Car)s).brand()
39
Cast Tipo statico e tipo dinamico di una variabile tipo statico: quello dichiarato tipo dinamico: il tipo del riferimento assegnato alla variabile (T)var causa errore in compilazione se T non è compatibile con il tipo statico di var in esecuzione ( ClassCastException ) se T non è compatibile con il tipo dinamico di var Continua…
40
Cast OK: Car sottotipo di Shape Compila correttamente il tipo dichiarato di s è Shape Car e Shape sono compatibili Esegue correttamente s è un Car (il tipo dinamico di s è Car) Shape s = new Car(); Continua… Car c = (Car) s
41
Cast OK: Car sottotipo di Shape Compila correttamente il tipo dichiarato di s è Shape Smiley e Shape sono compatibili Errore a run time s non è uno Smiley Shape s = new Car(); Continua… Smiley c = (Smiley) s
42
Cast Attenzione anche qui … public static void printBrand(List l) { for (Shape s : l) // ClassCastException se s instance of Smiley System.out.println( ((Car)s.)brand() ); } Continua…
43
instanceof Permette di determinare il tipo dinamico di una variabile Quindi permette di evitare errori in esecuzione Esegue correttamente, perchè x è sicuramente un T x istanceof T è true solo se x ha tipo dinamico T if (x instanceof T) return (T) x
44
Cast Questo, finalmente, è corretto public static void printBrand(List l) { for (Shape s : l) if (s instanceof Car) System.out.println( ((Car)s.)brand() ); }
45
Domanda E se volessimo disegnare solo le Shape s che sono Car s?
46
Risposta // disegna tutte le Cars della GWin public void paint(){ for (Shape c:shapes) if (c instanceof Car) c.draw(g); }
Presentazioni simili
© 2024 SlidePlayer.it Inc.
All rights reserved.