• Aucun résultat trouvé

7.2.2 ♥ L’arbre de toutes les classes

En Java l’h´eritage est simple : chaque classe poss`ede au plus une super-classe directe. En fait, il y a une classe particuli`ere, nomm´ee Object, qui n’a pas de super-classe, et toutes les autres classes ont exactement une super-classe directe. Par cons´equent, l’ensemble de toutes les classes, muni de la relation est sous-classe directe de, constitue une unique arborescence dont la racine est la classe Object.

Ainsi, les variables et m´ethodes qui composent un objet ne sont pas toutes d´efinies dans la classe de celui-ci : il y en a une partie dans cette classe, une partie dans sa super-classe, une autre partie dans la super-classe de la super-classe, etc. Cela introduit la question de la recherche des m´ethodes : un message ayant ´et´e envoy´e `a un objet, la r´eponse pertinente doit ˆetre recherch´ee dans la classe de celui-ci ou, en cas d’´echec, dans la super-classe de celle-l`a, puis dans la super-classe de la super-classe, et ainsi de suite, en remontant le long de la branche de l’arbre d’h´eritage, jusqu’`a trouver une classe dans laquelle on a pr´evu de r´epondre au message en question.

Le proc´ed´e de recherche des m´ethodes est un probl`eme important, dans tous les langages qui pratiquent l’h´eritage38. Il peut ˆetre trait´e `a la compilation, on parle alors de liaison statique, ou bien `a l’ex´ecution, on dit

qu’on pratique alors la liaison dynamique. La liaison statique est plus efficace, puisque les incertitudes sont lev´ees avant que l’ex´ecution ne commence, mais la liaison dynamique est beaucoup plus souple et puissante. Comme la suite le montrera, Java met en œuvre un savant m´elange de liaison statique et dynamique.

7.3

Red´efinition des m´ethodes

7.3.1 Surcharge et masquage

Que se passe-t-il lorsque des membres sp´ecifiques de la sous-classe ont le mˆeme nom que des membres h´erit´es ? Deux cas :

1. Si les entit´es qui ont le mˆeme nom ont des rˆoles ou des signatures diff´erentes, alors c’est un cas de surcharge et il est trait´e comme s’il s’agissait de deux membres de la mˆeme classe. Par exemple, rien ne s’oppose `a ce que cohabitent sans conflit dans la sous-classe une variable d’instance propre f et une m´ethode h´erit´ee f, ou deux m´ethodes de signatures diff´erentes dont une est h´erit´ee et l’autre non. 2. S’il s’agit au contraire de deux entit´es ayant le mˆeme rˆole et, dans le cas des m´ethodes, la mˆeme

signature alors il y a masquage : dans la sous-classe, le membre sp´ecifique masque le membre h´erit´e. Il y a plusieurs mani`eres d’acc´eder `a un membre masqu´e. Imaginons par exemple qu’on a introduit une mesure de qualit´e dans les points, et aussi une notion de qualit´e dans les pixels, ces deux notions n’ayant pas de rapport entre elles39:

class Point { int x, y; int qualite; ...

}

class Pixel extends Point { Color couleur;

int qualite; ...

}

Dans ces conditions, `a l’int´erieur d’une m´ethode de la classe Pixel, les expressions qualite et this.qualite d´esignent le membre qualite sp´ecifique de la classe Pixel. Mais les expressions

super.qualite et

((Point) this).qualite

d´esignent toutes deux le membre qualite h´erit´e de la classe Point.

38Notez que ce probl`eme est partiellement simplifi´e et optimis´e en Java par le fait qu’on n’y pratique que l’h´eritage simple.

Dans les langages `a h´eritage multiple, o`u une classe peut avoir plusieurs super-classes directes, le graphe d’h´eritage n’est plus un arbre. Dans ces langages, la recherche des m´ethodes devient une op´eration litigieuse et complexe.

39Si la qualit´e d’un pixel (en tant que pixel) n’a pas de rapport avec la qualit´e d’un point, c’est une maladresse que de donner

7.3.2 Red´efinition des m´ethodes

Si la d´efinition dans une sous-classe d’une variable ayant le mˆeme nom qu’une variable de la super-classe apparaˆıt souvent comme une maladresse de conception, la d´efinition d’une m´ethode ayant le mˆeme nom et la mˆeme signature qu’une m´ethode de la super-classe est au contraire une technique justifi´ee et tr`es utile.

En effet, la sous-classe ´etant une extension, c’est-`a-dire une am´elioration , de la super-classe, les objets de la sous-classe doivent r´epondre `a tous les messages auxquels r´epondent les objets de la super-classe, mais il est normal qu’il y r´epondent de mani`ere  am´elior´ee  : beaucoup de m´ethodes de la sous-classe font les mˆemes choses que des m´ethodes correspondantes de la super-classe, mais elles le font mieux , c’est-`a-dire en prenant en compte ce que les objets de la sous-classe ont de plus que ceux de la super-classe.

Exemple, courant mais fondamental : la m´ethode toString40 :

class Point { int x, y; ...

public String toString() {

return "(" + x + "," + y + ")"; }

}

class Pixel extends Point { Color couleur;

...

public String toString() {

return "[(" + x + "," + y + ");" + couleur + "]"; }

}

Il est facile de comprendre pourquoi la r´eponse `a un appel comme unPixel.toString() peut ˆetre vue comme une  am´elioration  de la r´eponse `a unPoint.toString() : si unPoint repr´esente un point et unPixel un pixel, les expressions

System.out.println(unPoint); System.out.println(unPixel); affichent, par exemple

(10,20)

[(30,40);java.awt.Color.red]

Note. ´Ecrite comme elle l’est, la m´ethode Pixel.toString pr´ec´edente a deux d´efauts :

– le mˆeme code (le traitement de x et y) est ´ecrit dans Point.toString et dans Pixel.toString, ce qui constitue une redondance, toujours regrettable,

– plus grave, la classe Pixel s’appuie ainsi sur des d´etails internes de la classe Point.

Une mani`ere bien pr´ef´erable d’´ecrire les m´ethodes red´efinies de la sous-classe consiste `a laisser les m´ethodes de la super-classe se charger du traitement de la partie h´erit´ee :

class Pixel extends Point { Color couleur;

...

public String toString() {

return "[" + super.toString() + ";" + couleur + "]"; }

}

Contraintes de la red´efinition des m´ethodes

1. On ne peut pas profiter de la red´efinition d’une m´ethode pour en restreindre l’accessibilit´e : la red´efinition d’une m´ethode doit ˆetre au moins  aussi publique  que la d´efinition originale. En particu- lier, la red´efinition d’une m´ethode publique41 doit ˆetre qualifi´ee public.

2. La signature de la red´efinition d’une m´ethode doit ˆetre identique `a celle de la m´ethode h´erit´ee. La signature d’une m´ethode se compose de trois ´el´ements :

40La m´ethode toString appartient `a tous les objets, puisqu’elle est d´efinie dans la classe Object.

41On notera que cela concerne en particulier la red´efinition – obligatoire, dans ce cas – des m´ethodes des interfaces (cf. section