Dans la pratique, une classe est rarement définie depuis zéro. Si on trouve une autre classe qui comporte déjà les fonctionnalités recherchées, il est plus simple de partir de celle-là en héritant de tout ce qu'elle contient.
import java.awt.Point; public class PointPolaire extends Point { public double getRayon() { return Math.sqrt((double)(this.x*this.x + this.y*this.y)); } public double getAngle() { return 2.0*Math.atan(((double)this.y)/(this.getRayon()+(double) this.x)); } }
Cet exemple définit un point du plan capable de donner ses coordonnées polaires. Plutôt que de réinventer une telle classe, on part de Point et on ajoute simplement les nouvelles fonctionnalités. La classe obtenue possède les nouvelles méthodes getRayon et getAngle, plus les attributs (x et y) et les méthodes (move, translate, etc) de la classe Point.
Remarque Chaque classe ne peut hériter que d'une seule autre classe. Le langage Java ne permet pas l'héritage multiple, bien que d'autres langages le proposent (par exemple le C++).
Seuls les constructeurs ne sont pas directement hérités. Notre exemple précédent possède donc uniquement un constructeur par défaut, ce qui est franchement insuffisant. Ajoutons un constructeur utile :
public class PointPolaire extends Point { ... public PointPolaire(int rayon, int angle) { super((int) rayon*Math.cos(angle), (int) rayon*Math.sin(angle)); } }
La première ligne d'un tel constructeur doit mentionner le mot-clé super suivi d'arguments. Ceci permet d'appeler le constructeur de la classe de base pour qu'il se charge d'initialiser la partie héritée de l'objet.
Si vous oubliez cette première ligne, le constructeur sans argument de la classe de base sera tout de même invoqué. Si aucun constructeur sans argument n'est défini dans la classe de base, une erreur sera signalée à la compilation.
Parfois les fonctionnalités héritées ne sont pas compatibles avec la nouvelle classe. On peut alors désirer remplacer les méthodes obsolètes par une version plus adéquate : c'est une redéfinition (à ne pas confondre avec une surcharge).
public class PointPolaire extends Point { ... @Override public String toString() { return "(" + this.getRayon() + " ; " + this.getAngle() + ")"; } }
Remarque Une redéfinition n'a lieu que si la signature de la nouvelle méthode reprend exactement la signature d'une méthode héritée. En cas de divergence, la nouvelle méthode sera interprétée comme une simple surcharge si vous oubliez l'annotation @Override.
On peut encore invoquer l'ancienne version de la méthode en utilisant le mot-clé super à la place de this.
public class PointPolaire extends Point { ... public String toRectangularString() { return super.toString(); } }
Grisaille. Définissez une classe Gris qui dérive de la classe Color mais ne permet de créer que des gris (c'est à dire des couleurs où les trois composantes sont égales). Pouvez-vous utiliser un objet de la classe Gris avec la méthode setBackground pour choisir la couleur de fond d'un composant ?
Métrique. La classe Paper sert à représenter la géométrie d'une feuille de papier (dans le but de faire des impressions). Malheureusement, cette classe utilise le système impérial obsolète pour toutes ses mesures.
Nuancier. On souhaite écrire une application qui se comporte comme un nuancier : elle permet de voir des couleurs côte à côte.
Pour cela, nous allons commencer par définir un composant graphique spécialisé nommé Nuance. Celui-ci devra avoir une taille préférée de 100 pixels de large par 100 pixels de haut, et devra indiquer les composants RVB de sa couleur de fond dans sa partie haute. De quelle classe pouvez-vous hériter ?
Écrivez une application qui prend une liste de couleurs sur la ligne de commande (au format #RRVVBB) et qui affiche ces couleurs horizontalement à l'aide du composant défini plus haut.
bob@box:~$ java Nuancier "#88E900" "#0088E9" "#E90088"
Remarque Pour que la fenêtre prenne une taille adaptée à son contenu plutôt qu'une taille arbitraire, utilisez la méthode pack à la place de la méthode setSize.