Dans tout ce que nous vennons de voir, les classes Java étaient toutes au même niveau. On peut faire un parallèle avec les fonctions du langage C où toutes les fonctions sont au même niveau et il n'est pas possible d'imbriquer des fonctions dans d'autres fonctions (comme dans le langage Pascal ).
Depuis la version 1.1, le langage Java permet de définir des classes à l'intérieur d'autres classes.
L'intérêt de ces classes qu'on imbrique dans d'autres classes est
class A { ... class B { .... } }
Tout comme les champs et méthodes, une classe imbriquée peut être qualifiée de static. Et comme on pouvait s'y attendre, les classes static ne peuvent faire référence aux champs et méthodes non static de la classe englobante.
Les classes définies à l'intérieur d'une classe ont accès à tous les champs (publiques ou privés) de la classe qui la contient. Autrement dit, tous les champs et méthodes d'une classe sont accessibles à partir de ses champs, méthodes et classes imbriquées.
Les classes static sont appelées classes imbriquées statiques (static nested class ) et les autres seront appelés classes intérieures (inner class ) Les classes intérieures ne peuvent définir des champs static.
Une instance d'une classe intérieure n'existe que s'il existe une instance de la classe qui la contient. Alors qu'une classe imbriquée static se comporte exactement comme une classe non imbriquée.
Les classes imbriquées (static ou pas) peuvent être déclarées abstract ou final. De plus, une classe imbriquée peut être public, private ou protected.
Dans la programmation graphique, il est très fréquent d'utiliser les classes imbriquées pour la gestions des évènements. Sans entrer dans les détails de la programmation graphique que nous verrons plus loin, signalons que Java fournit l'interface java.awt.event.MouseListener pour la gestion des évènements de la souris.
Le programmeur capture les évènements en implantant la méthode correspondante. Dans l'exemple qui suit, on définit une applet avec un bouton étiquetté par une chaîne de caractères qui se retourne à chaque clic.
interface java.awt.event.MouseListener { public void mousePressed(java.awt.event.MouseEvent e); public void mouseClicked(java.awt.event.MouseEvent e); public void mouseReleased(java.awt.event.MouseEvent e); public void mouseEntered(java.awt.event.MouseEvent e); public void mouseExited(java.awt.event.MouseEvent e); }
public class Click extends java.applet.Applet implements java.awt.event.MouseListener { java.awt.Button bouton; boolean b = true; public void init() { bouton = new java.awt.Button("Cliquez ici"); add("Center", bouton); bouton.addMouseListener(this); } public void mousePressed(java.awt.event.MouseEvent e) { b = !b; bouton.setLabel(b ? "Cliquez ici" : "ici zeuqilC"); } public void mouseClicked(java.awt.event.MouseEvent e) {} public void mouseReleased(java.awt.event.MouseEvent e) {} public void mouseEntered(java.awt.event.MouseEvent e) {} public void mouseExited(java.awt.event.MouseEvent e) {} }
Dans cet exemple, le programmeur ne s'intéresse pas à tous les évènements possibles mais qu'à un nombre limité d'entre eux. Par exemple, un bouton peut s'intéresser qu'au fait de cliquer. Dans ces cas, le composant qui implante l'interface MouseListener doit fournir l'implantation de toutes les méthodes de cette interface. Ce qui conduit le programmeur à fournir tout un ensemble de méthode vide.
Pour éviter cette inflation de méthodes vides, Java fournit, pour certaines des ces interfaces, une classe qui l'implante avec des méthodes vides. Par exemple, la classe MouseAdapter est définie comme suit:
Il suffit alors de se définir une sous classe de l'une de celles-ci et de ne redéfinir que les méthodes qui nous intéressent.
public class MouseAdapter implements MouseListener { public void mouseClicked(MouseEvent e) {} public void mousePressed(MouseEvent e) {} public void mouseReleased(MouseEvent e) {} public void mouseEntered(MouseEvent e) {} public void mouseExited(MouseEvent e) {} }
class MyMouseAdapter extends java.awt.event.MouseAdapter { private boolean b = true; private java.awt.Button bouton; public (MyMouseAdapter(java.awt.Button bouton) { this.bouton = bouton; } public void mousePressed(java.awt.event.MouseEvent e) { b = !b; bouton.setLabel(b ? "Cliquez ici" : "ici zeuqilC"); } }public class Click extends java.applet.Applet { private java.awt.Button bouton; public void init() { bouton = new java.awt.Button("Cliquez ici"); add("Center", bouton); MyMouseAdapter ma = new MyMouseAdapter(bouton); bouton.addMouseListener(ma ); } }
Avec cette manière de faire, on a réduit considérablement le nombre de méthodes vides que l'on est amené à programmer. Cependant, on vient d'augmenter le nombre de classes que l'on doit programmer et ce d'autant que la classe MyMouseAdapter n'a d'intérêt que pour la seule classe Click.
Une première approche consiste à utiliser une classe imbriquée pour encapsuler la classe MyMouseAdapter dans la classe Click.
Avec la classe imbriquée, il n'est plus nécessaire de passer d'argument dans constructeur de la classe imbriquée: les champs de la classe englobante sont accessible par la classe imbriquée.
public class Click extends java.applet.Applet { java.awt.Button bouton; public void init() { bouton = new java.awt.Button("Cliquez ici"); add("Center", bouton); MyMouseAdapter ma = new MyMouseAdapter(); bouton.addMouseListener(ma); } class MyMouseAdapter extends java.awt.event.MouseAdapter { boolean b = true; public void mousePressed(java.awt.event.MouseEvent e) { b = !b; bouton.setLabel(b ? "Cliquez ici" : "ici zeuqilC"); } } }
Une classe imbriquée peut être définie, non seulement à l'emplacement
d'un champ d'une autre classe, mais également partout une instruction
peut figurer. Dans ce cas, toutes les variables (arguments des méthodes,
variables locales) accessibles pour une instruction quelconque
l'est également pour les méthodes de la classe imbriquée et ce
à condition qu'elles soit déclarées final.
Les classes anonymes permettent de définir des classes locales sans devoir les nommer.
Une classe locale ne peut être qualifiée public, private, protected, ou static.
En effet, en tant que classe locale, elle est privée et
elle n'est pas visible en dehors du
bloc qui le définit.
Les classes non locales peuvent être, comme les classes ordinaires,
qualifées de private ou protected.
Les classes nommées peuvent être final ou abstract.
13.3 Classes locales
Ce sont les éventuels problèmes de synchronisation qui dicte cette restriction.
Un moyen de contourner l'impossiblite d'accéder et/ou de modifier les
varibales locales est d'utiliser un tableau contenant l'élément qu'on veut
manipuler.
public class Click extends java.applet.Applet {
public void init() {
final java.awt.Button bouton = new java.awt.Button("Cliquez ici");
add("Center", bouton);
class MyMouseAdapter extends java.awt.event.MouseAdapter {
boolean b = true;
public void mousePressed(java.awt.event.MouseEvent e) {
b = !b;
bouton.setLabel(b ? "Cliquez ici" : "ici zeuqilC");
}
}
MyMouseAdapter ma = new MyMouseAdapter();
bouton.addMouseListener(ma);
}
}
13.4 Classes anonymes
public class Click extends java.applet.Applet {
public void init() {
final java.awt.Button bouton = new java.awt.Button("Cliquez ici");
add("Center", bouton);
MouseAdapter ma = new java.awt.event.MouseAdapter {
boolean b = true;
public void mousePressed(java.awt.event.MouseEvent e) {
b = !b;
bouton.setLabel(b ? "Cliquez ici" : "ici zeuqilC");
}
};
bouton.addMouseListener(ma);
}
}
13.5 Classes imbriquées final, private, protected, ou static
Next: 14 Entrées-Sorties
Up: Java: Le langage
Previous: 12 Conversions et promotions
Touraivane
6/12/1998