240 likes | 436 Views
Dispatch. Overriding vs overloading. Notare che esistono due fasi nella selezione del metodo da invocare: Fase statica: risoluzione dell’overloading determina il tipo del metodo, in funzione del tipo statico degli argomenti presenti nel messaggio Fase dinamica: dispatch
E N D
Overriding vs overloading • Notare che esistono due fasi nella selezione del metodo da invocare: • Fase statica: risoluzione dell’overloading • determina il tipo del metodo, in funzione del tipo statico degli argomenti presenti nel messaggio • Fase dinamica: dispatch • determina il corpo del metodo, in funzione del tipo dinamico del parametro implicito (ovvero, del destinatario del messaggio)
Polimorfismo – run time • Dispatch articolato di quanto abbiamo visto … • Metodi • dispatch dinamico, con le seguenti eccezioni: • metodi private, chiamate via super • Metodi di classe (static) • dispatch è sempre statico • Campi • dispatch è sempre statico, sia per variabili di istanza, sia per variabili di classe (o static) Continua…
Invocazione di metodi • exp.m(a1,..., an) • per definire precisamente l’effetto della chiamata dobbiamo analizzare tre aspetti: • selezione statica • decide se è corretto invocare m(…) su exp, ovvero se esiste un metodo da invocare • determina il tipo del metodo da invocare • dispatch • determina il corpo del metodo da invocare
Selezione statica exp.m(a1,..., an) Due fasi: • Determina il tipo di exp • Determina la firma T m(T1,…Tn) del metodo da invocare in base al tipo degli argomenti a1,...,an In questa fase (statica) • tipo = tipo statico
Selezione Statica – Fase 1 exp.m(a1,..., an) • Determina il tipo statico S di exp: • exp = super: • Sè la superclasse della classe in cui l’invocazione occorre: • exp = this: • Sè la classe in cui l’invocazione occorre • in tutti gli altri casi: • Sè il tipo dichiarato per exp
Selezione statica – Fase 2 exp.m(a1,..., an)exp:S • Determina la firma del metodo da invocare • calcola il tipo degli argomenti, a1:S1,.... an:Sn • seleziona in S il metodo T m(T1,....,Tn)tale che Si<:Ti e m() è accessibile dal contesto di chiamata • se S non ha un metodo m() con le caratteristiche desiderate, ripeti il passo 2 sul supertipo di S (ognuno dei supertipi di S ), finché non trovi un metodo oppure esaurisci la gerarchia.
Selezione statica e overloading • L’algoritmo appena visto assume che ogni classe contenga al più una versione del metodo da invocare • Che succede se esiste una classe contiene più di una versione? • Che succede se una classe ed una superclasse contengono diverse versioni dello stesso metodo? • Sono entrambi casi di overloading, e la selezione statica deve risolverlo • Selezione statica richiede overloading resolution
Selezione statica – Fase 2 rivista exp.m(a1,..., an)exp:S • Determina la firma del metodo da invocare • calcola il tipo degli argomenti, a1:S1,.... an:Sn • determina il best matchT m(T1,...,Tn)per l’invocazione m(a1:S1,… an:Sn), a partire da S • Se trovi una sola firma ok, altrimenti errore
Best Match exp.m(a1:S1,..., an:Sn)exp:S 1. Determina l’insieme dei metodi applicabili APP(S, m(S1, ..., Sn)) = {U1.m(T11,...,T1n),...,Uk.m(Tk1,...,Tkn)} tali che, per ogni jin[1..k] • S<:Uj (quindi: esamina S ed i supertipi di S) • m(Tj1, …. Tjn) è definito in Uj ed è visibile nel punto della chiamata exp.m(a1,…,an). • Si <: Tji per ogni i in [1..n] 2. Se l’insieme è vuoto fallisci
Best Match • Altrimenti, calcola l’insieme dei metodi migliori BEST(S,m(a1:S1,…,. an:Sn)) rimuovi da APP(S, m(a1:S1, ... an:Sn)) ogni Up.m(Tp1, ..., Tpn) tale che esiste un metodo migliore, ovvero un metodo Uq.m(Tq1,...,Tqn) tale che -Uq <:Up (è definito in una superclasse più vicina aS) - Tqi<:Tpi (ha tipi degli argomenti piu vicini agli Si) • Se BEST(S,m(a1:S1,…,an:Sn)) contiene più di un metodo, fallisci. Altrimenti l’unico metodo nell’insieme e` il best match per la chiamata exp.m(a1,...,an)
Best Match – Esempi class A { public void m(int i) { System.out.println("A.m(int)"); } } class B extends A { public void m(String s) { System.out.println("B.m(String)"); } } class over { public static void main(String[] args) { B b = new B(); A a = new B(); a.m(1) b.m(“a string”) ; b.m(1); } } APP(A, m(int)) = { A.m(int) } APP(B, m(String)) = { B.m(String) } APP(B, m(int)) = { A.m(int) } // APP(A,m(int)) = {A.m(int)} // APP(B,m(String))= {B.m(String)} // APP(B,m(int)) = {A.m(int)}
Best Match – Esempi class A { public void m(int i) { System.out.println("A.m(int)"); } } class B extends A { public void m(String s) { System.out.println("B.m(String)"); } } class over { public static void main(String[] args) { B b = new B(); A a = new B(); a.m(1) b.m(“a string”) ; a = b; a.m(“a string”); } } APP(A, m(int)) = { A.m(int) } APP(B, m(String)) = { B.m(String) } APP(A, m(String)) = { } // APP(A,m(int)) = {A.m(int)} // APP(B,m(String))= {B.m(String)} // APP(A,m(string))= {}
Best Match – Esempi class A { public void m(int i) { System.out.println("A.m(int)"); } } class B extends A { public void m(double f) { System.out.println("B.m"); } } class over { public static void main(String[] args) { B b = new B(); A a = new B(); a.m(1); b.m(1.5); b.m(1); } } // APP(A,m(int)) = {A.m(int)} // APP(B,m(double))= {B.m(double)} // APP(B,m(int)) = {A.m(int),B.m(double)} // BEST(B.m(int)) = {A.m(int),B.m(double)}
Best Match – Esempi class A { public void m(double g) { System.out.println("A.m"); } } class B extends A { public void m(int i) { System.out.println("B.m"); } } class over { public static void main(String[] args) { B b = new B(); A a = new B(); a.m(1); b.m(1.5); b.m(1); } } // APP(A,m(int)) = {A.m(double)} // APP(B,m(double))= {A.m(double)} // APP(B,m(int)) = {A.m(double),B.m(int)} // BEST(B.m(int)) = {B.m(int)}
Best Match – Esempi class A { public void m(int i, float f) { /* just return */} public void m(float f, int i) { /* just return */} } class test { public static void main(String[] args) { A a = new A(); a.m(1, 1); } // APP(A, m(int,int)) = { A.m(int,float), A.m(float,int) } // BEST(A,m(int,int)) = { A.m(int,float), A.m(float,int) }
Invocazione di metodi exp.m(a1,..., an) • per definire precisamente l’effetto della chiamata dobbiamo analizzare tre aspetti: • selezione statica: determina la firma del metodo da invocare • calcolo del best match • dispatch dinamico: determina il corpo del metodo da invocare • se il dispatch è statico esegui il corpo del metodo determinato dalla selezione statica • altrimenti esegui il corpo del metodo con il tipo determinato dalla selezione statica che trovi a partire dal tipo dinamico di exp
Esempio class A { public void m(double d){System.out.println("A.m(double)"); public void m(int i) { System.out.println(“A.m(int)"); } } class B extends A { public void m(double d){System.out.print(“B.m(double)”); } } class over { public static void main(String[] args) { { A a = new B(); a.m(1.5); } } // Selezione statica:BEST(A, m(double)) = { A.m(double) } // Dispatch: B ridefinisce m(double). Quindi eseguiB.m(double)
Esempio class A { public void m(double d){ System.out.println("A.m(double)"); public void m(int i) { System.out.println(“A.m(int)"); } } class B extends A { public void m(double d){System.out.print(“B.m(double)”); } } class over { public static void main(String[] args) { { A a = new B(); a.m(1); } } // Selezione statica:BEST(A, m(int)) = { A.m(int) } // Dispatch: B non ridefinisce m(int). Quindi eseguiA.m(int)
Esempio class A { public void m(double d){ System.out.println("A.m(double)"); public void m(int i) { System.out.println(“A.m(int)"); } } class B extends A { public void m(double d){System.out.print(“B.m(double)”); } } class over { public static void main(String[] args) { { B b = new B(); b.m(1); } } // Selezione statica:BEST(A, m(int))={A.m(int),B.m(double)}
Metodi private : dispatch statico • Essendo private , non sono accessibili alle sottoclassi. • Quindi le sottoclassi non possono fare overriding di questi metodi • Dispatch può essere deciso dal compilatore Continua…
Metodi private : dispatch statico class A { public String test() { return this.sd() + " , " + this.dd();} private String sd(){ return "A.sd()"; } public String dd() { return "A.dd()"; } } class B extends A { public String sd() { return "B.sd()"; } public String dd() { return "B.dd()"; } } . . . // new B().test() = “A.sd(), B.dd()” // new A().test() = “A.sd(), A.dd()” dispatch statico: A.sd() dispatch dinamico: risolto a run time
Chiamate via super: dispatch statico class A { public String test() { return dd();} public String dd() { return "A.dd()"; } } class B extends A { public String dd(){ return (super.dd() + " , " +"B.dd()"); } } . . . // super.dd() invoca sempre A.dd() // new B().test() = “A.dd(), B.dd()” // new A().test() = “A.dd()”
Campi: dispatch statico • class C { • String str = "C"; • public void m() { System.out.println(str); } • } • class D extends C { • String str = "D"; • public void n() { System.out.println(str); } • } • . . . • D d = new D(); • d.m(); // C • d.n(); // D • System.out.println(d.str); // D • C c = d; • c.m(); // C • ((D)c).n(); // D • System.out.println(c.str);// C