B
démarre dans la vie avec toutes les
méthodes de la classe parente A
.
L'objet b
possède donc une méthode g et une
méthode f. Le code compile et affichera :
Je suis f de de A
B
possède la nouvelle méthode f.
Le code compile et affichera :
Je suis f de de BOn note que l'occurence de f dans le corps de g n'est pas résolue statiquement, c'est à dire en considérant la définition de f de la classe
A
. On parle de liaison tardive.b
(de type B
) vers A
peut rester implicite,
(Java confond héritage et sous-typage, c'est à dire qu'une classe
construite par héritage appartient naturellement au type de sa classe
parente), la conversion inverse (de a de type A
vers B
) ne va pas de soit.
En effet cette conversion doit être explicitée et elle entraîne une
vérification à l'exécution (qui ici n'échoue pas car la
variable a contient bien un objet de classe B
).
On doit donc écrire :
public static void main (String [] argv) { A a = new B () ; a.g() ; a.h() ; B b = (B)a ; // ICI b.g() ; b.h() ; } } |
A
(c'est-à-dire dont le compilateur pense qu'il est de
classe A
), n'a pas de méthode h, on doit donc
supprimer l'appel de méthode a.h()
Je suis f de de B Je suis f de de B Je suis f de de BEn effet les conversions de types sont justes des vérifications et ne changent pas la classe de l'objet.
a
est bien
B
, mais le compilateur ne veut pas le savoir.
Pour comprendre que le compilateur n'est pas si crétin.
Il faut noter que parfois le compilateur ne peut pas connaître la
classe exacte d'un objet :
static void appelerH(A a) { a.h() ; } |
static void appelerH(A a) { ((B)a).h() ; } |
ClassCastException
, que bizarrement on est pas obligé de
déclarer.HInstit
par héritage :
import java.io.* ; class HInstit extends Instit { HInstit(Lexer lexer) { super(lexer) ; } void parseF() { … } void parseL() { … } void parse() { … } public static void main(String [] argv) { Lexer lexer = new Lexer (new StringReader (argv[0])) ; HInstit i = new HInstit (lexer) ; i.parse() ; } } |
Instit
.super(lexer)
dans le
constructeur de la classe héritante.tok
ou step
par private
, car alors la classe
héritante n'y aurait plus accès.
On notera que l'absence de qualificateur signifie « visible de toutes
les classes du même package », que protected
signifie
« visible de toutes les classes du même package et des classes
héritantes », et que public
signifie « visible de
partout ».