Adloun

Classes abstraites et interfaces

Cours · programmation Java (école d'ingénieur), chapitre 10 · école d'ingénieur, informatique · le début du chapitre, la suite sur Adloun

Au chapitre précédent, la classe Forme avait une méthode aire() qui renvoyait . Ce n'était qu'un pis-aller : une « forme » sans plus de précision n'a pas d'aire, et personne ne devrait jamais créer un objet new Forme("?"). Ce que l'on voulait dire, c'est que toute forme concrète doit savoir calculer son aire, sans pouvoir dire comment au niveau de Forme.

Java offre deux outils pour exprimer cela. La classe abstraite est une classe incomplète : elle factorise du code commun, mais laisse certaines méthodes à écrire aux sous-classes. L'interface va plus loin : c'est un pur contrat, une liste de méthodes qu'une classe s'engage à fournir, et une classe peut signer autant de contrats qu'elle veut. Les interfaces sont partout dans la bibliothèque Java : savoir trier des objets, les parcourir, les comparer, c'est savoir implémenter des interfaces.

Objectifs du chapitre

  • Déclarer une classe et des méthodes abstraites, et comprendre ce que le compilateur exige alors des sous-classes.
  • Déclarer une interface, l'implémenter (implements), en implémenter plusieurs à la fois.
  • Choisir entre classe abstraite et interface.
  • Utiliser les méthodes default et static des interfaces.
  • Rendre des objets triables avec Comparable, et les trier autrement avec un Comparator.
  • Programmer « vers l'interface », et connaître les interfaces scellées et les classes anonymes.

10.1 Classes abstraites

10.1.1 Méthodes et classes abstraites

Définition 10.1Méthode abstraite, classe abstraite

Une méthode abstraite est une méthode déclarée sans corps, avec le modificateur abstract : abstract double aire();. Une classe qui contient une méthode abstraite doit être déclarée abstract. Une classe abstraite ne peut pas être instanciée : on ne peut pas écrire new suivi de son nom.

Reprenons les formes. La classe Forme déclare deux méthodes abstraites, que chaque forme fournira, et une méthode concrète, decrire(), écrite une fois pour toutes en s'appuyant sur les deux autres.


abstract class Forme {
    abstract double aire();                 // pas de corps : chaque forme le fournit
    abstract String nom();

    String decrire() {                      // méthode concrète, commune à toutes
        return nom() + " d'aire " + String.format("%.3f", aire());
    }
}

class Cercle extends Forme {
    private final double r;
    Cercle(double r) { this.r = r; }
    @Override double aire() { return Math.PI * r * r; }
    @Override String nom() { return "cercle"; }
}

class Rectangle extends Forme {
    private final double l, h;
    Rectangle(double l, double h) { this.l = l; this.h = h; }
    @Override double aire() { return l * h; }
    @Override String nom() { return "rectangle"; }
}

class Triangle extends Forme {
    private final double a, b, c;
    Triangle(double a, double b, double c) { this.a = a; this.b = b; this.c = c; }
    @Override double aire() {               // formule de Héron
        double p = (a + b + c) / 2;
        return Math.sqrt(p * (p - a) * (p - b) * (p - c));
    }
    @Override String nom() { return "triangle"; }
}

Avec le tableau


Forme[] dessin = { new Cercle(1.0), new Rectangle(2.0, 0.9), new Triangle(3, 4, 5) };

et une boucle qui affiche f.decrire() pour chaque forme :


cercle d'aire 3.142
rectangle d'aire 1.800
triangle d'aire 6.000

Le polymorphisme fonctionne exactement comme au chapitre 9 : decrire(), écrite dans Forme, appelle nom() et aire(), et c'est la version de l'objet réel qui répond. La différence est que Forme n'a plus à inventer une aire factice.

10.1.2 Ce que le compilateur exige

Une classe abstraite donne deux garanties, vérifiées à la compilation.

Proposition 10.2Garanties d'une classe abstraite
  • Une classe abstraite ne peut pas être instanciée.
  • Une sous-classe concrète (non abstraite) doit redéfinir toutes les méthodes abstraites dont elle hérite. Sinon, elle doit elle-même être déclarée abstract.

Par conséquent, tout objet dont le type statique est Forme possède à coup sûr une méthode aire() effective.

Les deux erreurs correspondantes :


Forme f = new Forme();

E1.java:3: error: Forme is abstract; cannot be instantiated
        Forme f = new Forme();
                  ^

class Carre extends Forme {
    private double c;
    @Override double aire() { return c * c; }
}

E2.java:10: error: Carre is not abstract and does not override abstract method nom() in Forme
class Carre extends Forme {
^

Le second message est une aide précieuse : il donne le nom exact de la méthode oubliée. Dans un projet réel, ajouter une méthode abstraite à une super-classe fait apparaître la liste complète des sous-classes à compléter.

Attention

Une classe abstraite peut avoir des attributs et des constructeurs (appelés par super(...) depuis les sous-classes), et des méthodes concrètes. « Abstraite » ne veut pas dire « vide » : cela veut dire « incomplète ». On peut d'ailleurs déclarer abstract une classe sans aucune méthode abstraite, simplement pour interdire de l'instancier.

10.2 Interfaces

10.2.1 Un contrat

Définition 10.3Interface

Une interface est un type qui déclare des méthodes sans (en général) les implémenter : ```java

interface Mesurable { double longueur(); } ` Ses méthodes sont implicitement public et abstract. Une classe **implémente** une interface en le déclarant (class Segment implements Mesurable) et en fournissant une méthode public pour chacune des méthodes de l'interface. Une interface n'a ni constructeur ni attribut d'instance.

Une interface définit un type, comme une classe : on peut déclarer une variable Mesurable m, un paramètre ou un tableau Mesurable[], et y ranger n'importe quel objet d'une classe qui implémente Mesurable. Le polymorphisme s'applique : la méthode exécutée est celle de l'objet.

La suite du cours est sur Adloun

Le chapitre en entier, formules et figures comprises, avec le tuteur, les fiches, les QCM et les exercices.

Lire la suite du cours

En accès libre, sans inscription.

Exercices corrigés de ce chapitre

Lire la suite du cours →