Dispatch. Overriding vs overloading Notare che esistono due fasi nella selezione del metodo da...
-
Upload
antonino-pace -
Category
Documents
-
view
215 -
download
0
Transcript of Dispatch. Overriding vs overloading Notare che esistono due fasi nella selezione del metodo da...
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 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:
1. Determina il tipo di exp
2. 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:1. exp = super:
• S è la superclasse della classe in cui l’invocazione occorre:
2. exp = this: • S è la classe in cui l’invocazione occorre
3. 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 1. calcola il tipo degli argomenti, a1:S1,.... an:Sn2. seleziona in S il metodo T m(T1,....,Tn) tale
che Si <:Ti e m() è accessibile dal contesto di chiamata
3. 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 invocare1. calcola il tipo degli argomenti, a1:S1,....
an:Sn
2. determina il best match T 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 j in [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
3. 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 a S) - Tqi <: Tpi (ha tipi degli argomenti piu vicini agli Si)
4. 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
APP(A, m(int)) = { A.m(int) }
APP(B, m(String)) = { B.m(String) }
APP(B, m(int)) = { A.m(int) }
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); }}
Best Match – Esempi
// APP(A,m(int)) = {A.m(int)}// APP(B,m(String))= {B.m(String)}// APP(B,m(int)) = {A.m(int)}
Best Match – Esempi
APP(A, m(int)) = { A.m(int) }
APP(B, m(String)) = { B.m(String) }
APP(A, m(String)) = { }
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))= {}
Best Match – Esempiclass 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 – Esempiclass 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 esegui B.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 esegui A.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 staticoclass 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(); // Cd.n(); // D System.out.println(d.str); // DC c = d;
c.m(); // C
((D)c).n(); // D
System.out.println(c.str); // C