Ainsi que nous l'avons vu, la compilation d'une application
réalise un contrôle de type statique
qui prend en compte la possibilité de définir des sous-classes et par-là
une hiérarchie de classes.
Ce mécansime se traduit au niveau du «bytecode»
produit par le compilateur
static) : elles
sont traitées comme les variables d'instance et peuvent comme
elles être masquées.
Le principe est donc simple : la signature de la méthode à invoquer
étant fixée et le type de l'objet auquel elle est appliquée
connu, une méthode de signature correcte est recherchée en partant de la classe de l'objet et en remontant jusqu'à la classe
Object.
La première rencontrée, qui Eatisfait le profile, est alors invoquée.
Insistons sur le fait, que ce n'est pas le type de la référence
qui importe mais le type réel de l'objet référencé.
De plus, ainsi qu'il a été dit, la méthode s'exécute
du point de vue de la vue des variables dans le contexte de la classe
où elle est définie.
Cela correspond au schéma suivant :
Par contre, toute invocation de méthode ultérieure est réalisée selon le principe de liaison tardive, et donc en se fondant sur le type réel de l'objet dans la recherche de la méthode satisfaisant le profil qui a été déterminé par typage statique lors de la compilation.
l'invocation de la méthode
methode2
donnera lieu à une recherche de cette méthode avec le profil
(déterminé à la compilation) à partir de la classe
CL4
(type de l'objet courant).
L'exemple suivant résume les différents aspects tant de la liaison statique que de l'accès aux variables d'instance :
--> cat Liaison1.java
class A {
string a = "a dans A";
String b = "b dans A";
String c = "c dans A";
void fonc1( ){
System.out.println("fonc1 dans A");
System.out.println("----------");
fonc2( ); fonc3( );
System.out.println("**********");
}
void fonc2( ){
System.out.println("fonc2 dans A");
System.out.println(a); System.out.println(b);
System.out.println(c); System.out.println("----------");
}
void fonc3( ){
System.out.println("fonc3 dans A");
System.out.println("----------");
}
}
class B extends A{
String a = "a dans B";
String b = "b dans B";
void fonc2( ){
System.out.println("fonc2 dans B");
System.out.println(a); System.out.println(b);
System.out.println(c); System.out.println("----------");
}
void fonc3( ){
System.out.println("fonc3 dans B");
System.out.println(a); System.out.println(b);
System.out.println(c); System.out.println("----------");
}
}
class C extends B{
String a = "a dans C";
String c = "c dans C";
void fonc2( ){
System.out.println("fonc2 dans C");
System.out.println(a); System.out.println(b);
System.out.println(c); System.out.println("----------");
}
}
public class Liaison1 {
public static void main(String[ ] arg){
B b = new C( );
b . fonc1 ( );
}
}
--> java Liaison1
fonc1 dans A // A.fonc1 car objet de type C et fonc1 non déf. dans C et B
----------
fonc2 dans C // C.fonc2 car objet de type C et fonc2 non déf. dans C:
a dans C // vision de a dans C
b dans B // vision de b dans B car non masqué dans C
c dans C // vision de c dans C
----------
fonc3 dans B // B:fonc3 car objet de type C et fonc2 non déf. dans C:
a dans B // la vision de a dans B
b dans B // la vision de b dans B
c dans A // la vision de c dans A (car non masqué dans B)
----------
********** // retour de l'appel initial A.fonc1
|