next up previous contents index
Next: 9 Packages Up: Java: Le langage Previous: 7 Héritage

Subsections

8 Les interfaces

  

Le langage Java ne permet pas de l'héritage multiple . Il pallie ce manque par l'introduction des interfaces . Le choix délibéré de Java de supprimer l'héritage multiple est dicté par un souci de simplicité.

 

A TERMINER
héritage diamant

Pour supprimer les problèmes liés à l'héritage multiple, les interfaces sont des ``sortes de classes'' qui ne possèdent que des champs static final (autant dire des constantes) et des méthodes abstraites.

En fait, les interfaces sont un moyen de préciser les services qu'une classe peut rendre. On dira qu'une classe implante une interface Z si cette classe fournit les implantations des méthodes déclarées dans l'interface Z. Autrement dit, la définition d'une interface consiste se donner une collection de méthodes abstraites et de constantes. L'implantation de ces méthodes devra évidemment être fournie par les classes qui se réclament de cette interface.

Bref, une interface est une classe abstraite dans laquelle, il n'y a ni variables d'instances et ni méthodes non abstraites.

Les interfaces ne fournit pas l'héritage multiple car :

8.1 Déclaration des interfaces

            Comme les classes, les interfaces sont constituées de champs et de méthodes ; mais, comme nous l'avons déjà dit, il existe de très fortes contraintes sur la nature des membres d'une interface :

La syntaxe de la déclaration d'une interface est la suivante :

 

interface Service {
        int MAX = 1024 ;
        ...
        int une_méthode(...) ;
        ...
}

Par convention les noms des interfaces commencent par une lettre majuscule et se terminent par ``able'' ou ``ible''. Dans nos exemples, on n'appliquera pas ces conventions.

8.1.1 Interface publique

  Une interface peut être qualifiée de public. Une interface public peut être utilisée par n'importe quelle classe. En l'absence de ce qualifier, elle ne peut être utilisée que par les seules classes appartenant au même package (voir 9) que l'interface.

Contrairement aux classes, on ne peut qualifier une interface de private ou protected.

8.1.2 Membres des interfaces

               

Les champs d'une interface sont des champs static. Toutes les règles d'initialisation des champs statiques s'appliquent ici.

Les qualifiers transcient, volatile ou synchronized ne peuvent être utilisés pour les membres des interfaces. De même, les qualifiers private et protected ne doivent être utilisés pour les membres des interfaces.

8.2 Implanter des interfaces

Les interfaces définissent des ``promesses de services''. Mais seule une classe peut rendre effectivement les services qu'une interface promet. Autrement dit, l'interface toute seule ne sert à rien : il nous faut une classe qui implante l'interface. Une classe qui implante une interface le déclare dans son entête

 

 

class X implements Service {
        ...
        int une_méthode(...) {
                ...
        }
        ...
}

Par cette déclaration, la classe X promet d'implanter toutes les méthodes déclarées dans l'interface Service. La classe X doit donc fournir l'implantation des méthodes précisées dans l'interface Service; on devra donc trouver dans le définition de cette classe, l'implantation de la la méthode une_méthode.

La signature de la méthode doit évidemment être la même que celle promise par l'interface. Dans le cas contraire, la méthode est considérée comme une méthode de la classe et non une implantation de l'interface.

Si une méthode de même signature existe dans la classe mais avec un type de retour différent une erreur de compilation est générée.

8.3 Utiliser des interfaces

Comme pour les classes, on peut définir des références ayant le type d'une interface. Par contre, il n'est pas possible de définir un objet de ce type : les interfaces sont une sorte de classes abstraites !
 

Service s ;

Qu'est-ce qu'une référence de type interface ? Et bien, c'est une référence contient

Moyennant ces précisions, une référence vers une interface peut être utilisée partout où une référence vers un objet peut être utilisée.

Pourquoi vouloir désigner un objet, non pas par rapport à sa classe, mais par rapport à l'interface qu'elle cette implante ? Voici un exemple d'utilisation. Soit l'interface suivante :

 

interface Représentable {
    void dessiner();
    void tourner(int angle);
    void translater(int depl);
    }

permettant de dessiner et effectuer une rotation ou une translation sur des formes géométriques. Chaque forme (un carrée, un cercle, un polygone, etc.) devra implanter cette interface pour faire partie de l'ensemble de formes représentatable.

Imaginons, à présent, une classe Dessin veuille gérer un tableau de formes représentables. Quel est le type de ce tableau ?

La première solution consiste à définir un tableau Object [] en précisant que les éléments sont des instances de la classe Object; ce qui sera toujours vrai puisque la classe Object est la classe ancêtre de toute les classes. Cette solution est évidemment à éviter car ce tableau pourra, certes, contenir des formes représentables mais aussi n'importe quelle autre instance. Cette définition est bien trop large !

Comment faire pour restreindre le type des objets, que ce tableau peut contenir, aux seuls instances des classes ayant implanté l'interface Représentables ? Pour cela, il suffit de définir un tableau de type interface :

 

class Dessin  {
    private Représentable[] listeFormes;
    ...
}

Ainsi, cette classe pour, par exemple, implanter une méthode dessinerTout qui dessine l'ensemble des formes:

 

class Dessin  {
    private Représentable[] listeFormes;
    ...
    public void dessinerTout() {
        for (i = 0; i < sommet; i++) listeFormes[i].dessiner()
    }
}

8.3.1 Interface dérivée

  Tout comme les classes, les interfaces peuvent être organisées de manière hiérarchique à l'aide de l'héritage. Une classe ne peut être dérivée que d'une autre classe; de même, une interface ne peut être dérivée que d'une autre interface. Mais, contrairement aux classes, une interface peut étendre plusieurs interfaces.
 

interface A extends X {
    ...
}

interface A extends X, Y, Z {
    ...
}

Une interface dérivée hérite de toutes les constantes et méthodes des interfaces ancêtres; à moins qu'un autre champ de même nom ou une autre méthode de même signature soit redéfinie dans l'interface dérivée.

8.3.2 Redéfinition des champs

 

Tout comme pour les classes, les champs des interface peut être redéfinis dans une interface dérivée.

 

interface A { int info = 1; }
interface B extends A { int info = 2; }

La définition du champ info dans l'interface B masque la définition du champ info de l'interface A. Pour parler du champ info de l'interface A, on le notera A.info.

8.3.3 Héritage diamant

Un même champ peut être hérité de plusieurs manière pour une même interface:

 

interface A { char infoA = 'A'; }
interface B extends A { char infoB = 'B'; }
interface C extends A { char infoB = 'C'; }
interface D extends B, C { char infoD = 'D'; }
Le champ infoA est hérité par l'interface D de deux manières: une fois par l'interface B et une autre fois par celle de C. Mais il n'existera pas deux champs infoA dans l'interface D; il n'y en aura qu'un.


next up previous contents index
Next: 9 Packages Up: Java: Le langage Previous: 7 Héritage
Touraivane
6/12/1998