ENPC - Programmation - Séance 7

L'égalité entre anneaux: première approche

De la même manière que nous avons redéfini la méthode surface() dans la classe Anneau afin qu'elle donne le résultat attendu, nous voulons mainteant redéfinir la méthode same(), qui existait dans la classe Disque, afin qu'elle permette de tester l'égalité de deux anneaux (même centre, même rayon et même rayon interne).

Exercice 1: Redéfinissez la méthode same() dans Anneau.

Testez alors cette méthode sur le code suivant:

  Point p = new Point();
  Disque d1 = new Disque(p, 1);
  Disque d2 = new Disque(p, 1);
  Anneau a1 = new Anneau(p, 1, 2);
  Anneau a2 = new Anneau(p, 1, 2);
  System.out.println(d1.same(d2));
  System.out.println(a1.same(a2));
  System.out.println(d1.same(a1));
  System.out.println(a1.same(d1));
Expliquez les différents comportements constatés par le mécanisme de résolution de méthode appliqué successivement par le compilateur puis par la machine virtuelle Java (JVM).

Héritage implicite de Object

L'héritage est transitif: si une classe B hérite de A et que C hérite de B, alors la classe C hérite via B de toutes les méthodes et tous les champs de la classe A. Ainsi, comme toute classe qui n'hérite explicitement de rien hérite implicitement de la classe Object, toute classe dispose par héritage de toutes les méthodes définies dans la classe Object. Recherchez ces méthodes dans la documentation des API. Toutes ses méthodes sont donc héritées dans les classes Disque et Anneau, entre autres.

Exercice 2: Vérifiez que les classes Disque et Anneau possèdent bien, par héritage, la méthode toString() définie dans la classe Object. Pour cela, mettez en commentaire les méthodes toString() que vous avez pu définir dans les classes Disque et Anneau, et faites afficher le résultat de l'appel à la méthode toString() sur des références à des anneaux et à des disques.

L'égalité entre objets: une meilleure approche

Sachant que toute référence à une instance d'une classe peut être stockée dans une variable déclarée d'une super classe, on peut donc mettre n'importe quelle référence à n'importe quel instance de n'importe quelle classe dans une variable déclarée du type Object.
En utilisant les méthodes same() précédement définies, tester le code suivant:

  Point p = new Point();
  Disque d1 = new Disque(p, 1);
  Disque d2 = new Disque(p, 1);
  Object o = d;   // les variables o et d contienent la même référence 
  System.out.println(d1.same(d2));
  System.out.println(o.same(d2));

Expliquez le comportement constaté.

Exercice 3: Comme vous avez dû le constater, la classe Object définit une méthode equals(). Redéfinissez cette méthode dans les classes Disque et Anneau et testez les.

Connaître le type réel de la référence contenue dans une variable.

Nous avons déjà vu qu'une variable peut contenir des références à des instances de n'importe quelle classe qui soit une sous-classe de la classe déclarée de la variable. Pour savoir si le type réellement contenu dans une variable v est un sous-type de T, on peut utiliser l'opérateur instanceof qui donnera alors la valeur true à l'expression (v instanceof T)

Exercice 4: Écrire un programme qui déclare une variable o de type Object et qui lui affecte soit une instance de la classe Anneau, soit une instance de la classe Disque. Pour cela, on effectue un tirage aléatoire avec la méthode statique Math.random() (qui renvoie un double entre 0 et 1) et on choisira suivant si ce tirage est inférieur ou supérieur à 0,5. Une fois la variable o affectée, on affichera un message qui indique si o est un anneau ou non.

Interfaces

Une interface est un ensemble de déclarations de méthodes qui ne sont pas définies: au lieu d'avoir un corps entre accolades qui définit leur code comme dans les classes, leur déclaration est simplement suivie d'un point virgule. Pour définir une interface, il suffit de remplacer le mot clé class par interface:

  interface I {
    void m1(Object o);
    double m2();
  }

Au même titre qu'une classe, une interface définit un type qui permet de déclarer des variables, comme par exemple I i;. En revanche, une interface ne permet de créer aucun objet, aucune instance; elle ne peut avoir aucun constructeur. Elle ne peut d'ailleurs définir aucun champ (à part des constantes final static). Ainsi, une interface est seulement une "déclaration d'intention" qui dit que toute instance qui sera stockable dans une variable du type de l'interface (telle que i), sera capable de supporter toutes les méthodes déclarée dans I (les méthodes m1 et m2).

On dit qu'une classe C implémente ou réalise une interface I à deux conditions:

  1. elle revendique cette implémentation en déclarant:
    class C implements I { ... }
  2. chaque méthode déclarée par I est définie par C, c'est à dire dans notre exemple que C possède une définition de m1 et de m2 avec leur code.
On peut alors utiliser une variable déclarée du type de l'interface pour stocker une instance d'une classe qui l'implémente et appeler sur cette variable n'importe quelle méthode qui es tdéclarée par l'interface.

  I i = new C();
  i.m1(new Object());
  double d = i.m2(3.5);
Exercice 5: Définissez une interface Mesurable qui déclare une unique méthode de signature double surface(). Faites en sorte que les classes Disque et Anneau implémentent cette interface.

Exercice 6: Définissez, dans une classe Test, une méthode statique double somme(Mesurable[]) qui calcule la somme des surfaces des instances d'objets mesurables que contient le tableau qui lui est passé en argument. Testez cette méthode.

Exercice 7: Écrire une classe Carre, qui représente un carré par un Point qui est son coin (toujours le même, disons supérieur droit) et par un double qui est la taille de ses côtés. Écrire un constructeur et une méthode toString() pour cette classe, et lui faire implémenter l'interface Mesurable. Testez à nouveau la méthode somme() de l'exercice 6 en lui passant en argument un tableau contenant à la fois des Disque, des Anneau et des Carre.


Etienne.Duris[at]univ-mlv.fr - © École Nationale des Ponts et Chaussées - Janvier 2002 - http://www-igm.univ-mlv.fr/~duris/ENPC/