Java / Classes internes

publicité
Informatique / Programmation
Programmation orientée objet avec Java
14 : Classes internes
Jacques Bapst
[email protected]
Java / Classes internes
Classes internes
 Jusqu'à présent, les classes (et interfaces) que nous avons vues
étaient toutes des classes (et interfaces) de premier niveau (c'està-dire des membres directs des paquetages, sans imbrication).
 Le langage Java permet cependant de définir des classes à
l'intérieur d'autres classes.
On parle dans ce cas de classes internes (Nested Class).
 Il existe quatre types de classes internes :
 Les classes membres statiques
 Les classes membres
 Les classes locales
 Les classes anonymes
(Static Nested Class)
(Inner Class)
(Local Inner Class)
(Anonymous Inner Class)
Attention : D'un auteur à l'autre, le vocabulaire utilisé pour qualifier ces
différentes classes internes peut varier sensiblement.
EIA-FR / Jacques Bapst
PR1_14
2
Java / Classes internes
Classes membres statiques [1]
 Une classe membre statique est une classe définie comme un
membre statique d'une autre classe.
 Des interfaces peuvent également être déclarées comme
membres statiques d'une classe. Les remarques qui suivent
s'appliquent donc également aux interfaces membres statiques.
 Par analogie avec les méthodes statiques, on pourrait parler de
"classe de classe" (mais cela porte un peu à confusion).
 Une classe membre statique se comporte comme une classe de
premier niveau avec en outre la possibilité d'accéder aux membres
statiques de la classe qui la contient (classe englobante).
 Une classe membre statique a accès à tous les membres statiques
de sa classe englobante, y compris les membres privés (private).
 L'inverse est également vrai : les méthodes de la classe englobante
ont accès à tous les membres (statiques ou non-statiques) d'une
classe membre statique, y compris les membres privés.
EIA-FR / Jacques Bapst
PR1_14
3
Java / Classes internes
Classes membres statiques [2]
 Une classe membre statique a même accès à tous les membres
des autres classes membres statiques (classes "sœurs"), y compris
aux membres déclarés private de ces classes.
 Une classe membre statique peut être déclarée avec ses propres
modificateurs de contrôle d'accès. Ces modificateurs (public,
protected, private, aucun) possèdent les mêmes significations que
pour les autres membres d'une classe (champs et méthodes).
 En dehors de la classe englobante, une classe membre statique
est nommée en combinant le nom de la classe externe avec le
nom de la classe interne. Par exemple :
LinkedStack.Linkable node
 Restrictions :
• Une classe membre statique ne peut pas posséder le même nom
qu'une de ses classes englobantes.
• Une classe membre statique ne peut être englobée que dans une
classe de premier niveau ou dans une classe membre statique.
EIA-FR / Jacques Bapst
PR1_14
4
Java / Classes internes
Exemple d'interface membre statique
//===== Une classe qui implémente une pile sous forme de liste chaînée =====
public class LinkedStack {
// Interface membre statique qui définit la manière dont les objets sont liés
public static interface Linkable {
public Linkable getNext();
public void setNext(Linkable node);
}
// La tête de liste est un objet de type Linkable
Linkable head;
// Les corps des méthodes sont omis
public void push(Linkable node) { ... }
public Linkable pop() { ... }
}
//===== Cette classe implémente l'interface membre statique =====
public class LinkableInteger implements LinkedStack.Linkable {
// Les données et le constructeur du noeud
int i;
public LinkableInteger(int i) { this.i = i; }
// Données et méthodes requises pour implémenter l'interface
LinkedStack.Linkable next;
public LinkedStack.Linkable getNext() { return next; }
public void setNext(LinkedStack.Linkable node) { next = node; }
}
EIA-FR / Jacques Bapst
PR1_14
5
Java / Classes internes
Classes membres [1]
 Une classe membre est une classe qui est déclarée comme un
membre non-statique d'une classe englobante.
 Les interfaces ne peuvent pas être déclarées comme membres
non-statiques d'une classe.
 Une instance d'une classe membre est toujours associée à une
instance (un objet) de la classe englobante.
 Le code d'une classe membre a accès à tous les champs et à
toutes les méthodes (autant statiques que non-statiques et même s'ils
sont déclarés privés) de sa classe englobante et des classes "sœurs".
 Comme tous les autres membres de la classe, une classe membre
peut être déclarée avec ses propres modificateurs de contrôle
d'accès.
Ces modificateurs (public, protected, private, aucun) possèdent les
mêmes significations que pour les autres membres de la classe
(champs et méthodes).
EIA-FR / Jacques Bapst
PR1_14
6
Java / Classes internes
Classes membres [2]
 Restrictions :
• Une classe membre ne peut pas porter le même nom qu'une classe ou
qu'un paquetage englobant (une telle restriction ne s'applique pas aux
champs et aux méthodes).
• Les classes membres ne peuvent pas contenir de champs, de
méthodes ou de classe déclarés static (à l'exception des constantes
qui sont déclarées à la fois static et final).
 Pour instancier une classe membre à l'extérieur de la classe de
définition, il faut disposer d'une instance de la classe englobante.
 On utilisera cette instance avec l'opérateur new pour créer un objet
de la classe membre. Syntaxe : InstanceExt.new ClasseInterne
Exemple :
ExtClName
eObj = new ExtClName(…);
ExtClName.IntClName iObj = eObj.new IntClName(…);
// Objet externe
// Objet interne
et non pas :
ExtClName.IntClName iObj = eObj.new ExtClName.IntClName(…);
EIA-FR / Jacques Bapst
PR1_14
7
Java / Classes internes
Classes membres [3]
Complément
 Une syntaxe particulière est utilisée pour accéder explicitement
aux champs et méthodes d'instance de son objet englobant.
 Cette syntaxe n'est nécessaire que pour référencer un membre
d'une classe englobante qui est masqué par un membre du même
nom dans la classe interne (ce qui est à éviter !) :
Nom_Classe_Englobante . this . Nom_Membre
LinkedStack.this.head
 Il est également possible d'accéder à un champ masqué ou à une
méthode redéfinie d'une super-classe de la classe englobante :
Nom_Classe_Englobante . super . Nom_Membre
Reactor.super.run()
 Une classe de premier niveau peut étendre (spécialiser) une
classe membre ce qui introduit deux hiérarchies distinctes (la
hiérarchie de classes habituelle + une hiérarchie de confinement) qui
affectent les éléments visibles (portée).  A éviter !
EIA-FR / Jacques Bapst
PR1_14
8
Java / Classes internes
Exemple de classe membre
//===== Une classe qui implémente une pile sous forme de liste chaînée =====
public class LinkedStack {
// Interface membre statique qui définit la manière dont les objets sont liés
public static interface Linkable { ... }
// Contenu omis
private Linkable head;
public void push(Linkable node) { ... }
public Linkable pop() { ... }
// Contenu omis
// Contenu omis
// Cette méthode retourne un objet de type Enumeration pour l'objet LinkedStack courant
public java.util.Enumeration enumerate() { return new Enumerator(); }
// Classe membre qui implémente l'interface Enumeration
protected class Enumerator implements java.util.Enumeration {
Linkable current;
// Le constructeur utilise le champ privé head de la classe englobante
public Enumerator() { current = head; }
public boolean hasMoreElements() { return (current != null); }
public Object nextElement() {
if (current==null) throw new java.util.NoSuchElementException();
Object value = current;
current = current.getNext();
return value;
}
}
}
EIA-FR / Jacques Bapst
PR1_14
9
Java / Classes internes
Classes locales [1]
 Une classe locale est une classe qui est déclarée au sein d'un
bloc de code Java (généralement dans une méthode).
 Tout comme une variable locale, une classe locale n'est visible
qu'à l'intérieur du bloc dans lequel elle a été déclarée.
 Les classes locales sont déclarée à l'intérieur d'une classe
englobante et elles partagent de ce fait plusieurs caractéristiques
des classes membres.
 Les interfaces ne peuvent pas être déclarées localement.
 Le code d'une classe locale peut accéder à tous les membres (y
compris aux membres privés) de la classe englobante.
 Les classes locales peuvent également accéder à toutes les
variables locales et aux paramètres de méthode qui se trouvent
dans la portée de la définition locale de la méthode pour autant
qu'ils soient effectivement final (avec ou sans le modificateur)
(car la durée de vie d'une instance d'une classe locale peut être plus
longue que l'exécution de la méthode dans laquelle elle est déclarée).
EIA-FR / Jacques Bapst
PR1_14
10
Java / Classes internes
Classes locales [2]
 Les restrictions suivantes s'appliquent aux classes locales :
• Une classe locale n'est visible qu'au sein du bloc qui la définit; elle ne
peut jamais être utilisée hors de ce bloc.
• Les classes locales ne peuvent pas être déclarées public,
protected, private ou static. Ces modificateurs sont réservés aux
membres de la classe.
• Pour les mêmes raisons que les classes membres, les classes locales
ne peuvent pas contenir de champs, de méthodes ou de classes
statiques (à l'exception des constantes déclarées static final).
• Une classe locale ne peut pas avoir le même nom qu'une de ses
classes englobantes.
• Une classe locale ne peut accéder aux variables locales et
paramètres de méthode qui se trouvent dans sa portée que si ces
variables et paramètres sont effectivement final (avec ou sans le
modificateur final). Dans ce cas, le compilateur créera une copie de
ces variables locales car leur durée de vie peut être plus courte que
celle des instances de la classe locale.
EIA-FR / Jacques Bapst
PR1_14
11
Java / Classes internes
Exemple de classe locale
//===== Un exemple de classe locale utilisant des variables locales =====
public class TestLocalClass {
// Interface membre statique
public static interface IntHolder { public int getValue(); }
public static void main(String[] args) {
IntHolder[] holders = new IntHolder[10];
for (int i=0; i<10; i++) {
final int fi = i;
// Classe locale pouvant utiliser les variables locales déclarées (ou effectivement) final
class MyIntHolder implements IntHolder {
public int getValue() { return fi; }
}
holders[i] = new MyIntHolder(); // Instancie la classe locale
}
// La classe locale et la variable fi ne sont plus visibles mais on peut malgré tout utiliser
// le tableau d'instance holders et afficher les valeurs 0…9 (1)
for (int i=0; i<10; i++) System.out.println(holders[i].getValue());
}
}
(1)
Pour expliquer ce comportement assez surprenant, il faut savoir que chaque instance d'une
classe locale possède une copie privée de chaque variable locale effectivement final qu'elle
utilise. Ainsi, l'instance mémorise l'état des variables qui étaient dans sa portée au moment
où elle a été créée.
EIA-FR / Jacques Bapst
PR1_14
12
Java / Classes internes
Classes anonymes [1]
 Une classe anonyme est une classe locale qui ne possède pas
de nom.
 Une classe anonyme est soit :
• une sous-classe d'une classe parente existante
• une classe qui implémente une interface existante
(c'est donc également une sous-classe d'Object)
 Une classe anonyme combine la déclaration et l'instanciation
de la sous-classe sous la forme d'une expression qui peut
apparaître comme fragment d'une expression plus grande (par
exemple dans une invocation de méthode).
 Lorsqu'une sous-classe locale (ou classe implémentant une interface)
n'est utilisée qu'une seule fois, on peut envisager d'en faire une
classe anonyme qui place la définition et l'utilisation de la classe
au même endroit. Cela peut, dans certains cas, favoriser la
compacité et la lisibilité du code source.
EIA-FR / Jacques Bapst
PR1_14
13
Java / Classes internes
Classes anonymes [2]
 La création d'une classe anonyme fait intervenir une nouvelle
syntaxe qui combine la définition et l'instanciation de la classe.
 Pour la définir plus formellement, il faut distinguer les deux
situations possibles.
 Sous-classe anonyme :
new Nom_Classe_Parente( [ Liste_Param ] ) { Corps_Sous_Classe }
 Classe anonyme implémentant une interface :
new Nom_Interface() { Corps_Classe }
 Cette nouvelle syntaxe introduit une complication supplémentaire
sur le plan de la mise en page (indentation) car la création d'une
classe anonyme s'effectue généralement dans le cadre d'une
expression (voir exemple).
 A utiliser avec modération !
EIA-FR / Jacques Bapst
PR1_14
14
Java / Classes internes
Classes anonymes [3]
 Les classes anonymes constituent une forme particulière de
classes locales et toutes les restrictions mentionnées pour les
classes locales s'appliquent également aux classes anonymes.
 En plus, on peut mentionner la restriction suivante :
• Comme les classes anonymes ne possèdent pas de nom, il n'est
pas possible de définir explicitement des constructeurs
(elles possèdent uniquement le constructeur par défaut).
En remplacement, on peut cependant créer un initialiseur d'instance
qui pourra jouer pratiquement le même rôle qu'un constructeur.
 Quand utiliser une classe anonyme ?
• La classe possède un corps très court
• Une seule instance de la classe est nécessaire
• Le nom de la classe ne facilite pas la compréhension du code
 Il faut toujours privilégier la lisibilité du code source.
EIA-FR / Jacques Bapst
PR1_14
15
Java / Classes internes
Exemple de classe anonyme
//===== Un exemple de classe anonyme pour filtrer des fichiers dans un répertoire =====
public class TestAnonymousClass {
// Liste tous les fichiers du répertoire D:\Data possédant l'extension .java
public static void main(String[] args) {
File f = new File("D:\\Data");
// Le répertoire à énumérer
// La méthode list() prend en argument un objet de type FilenameFilter
// Une instance de la sous-classe anonyme de FilenameFilter est créée
// directement dans l'expression d'invocaton de la méthode list()
String[] fileList=f.list(new FilenameFilter() {
public boolean accept(File dir, String s) {
return s.endsWith(".java");
}
}); // N'oubliez pas la parenthèse et le point-virgule qui achèvent l'appel de la méthode
// Affichage de la liste des fichiers trouvés
for (int i=0; i<fileList.length; i++) {
System.out.println("File name : " + fileList[i]);
}
}
}
Noter la mise en page pour l'écriture des classes anonymes (conventions de codage Oracle).
EIA-FR / Jacques Bapst
PR1_14
16
Java / Classes internes
Remarques sur les classes internes [1]
 Les différents types de classes internes offrent des mécanismes
supplémentaires pour organiser et structurer le code source.
 En créant une classe interne, on limite leur niveau d'exposition en
les encapsulant au sein d'autres classes. Pour les classes
membres (statiques ou non), on peut limiter leur accès en utilisant
les modificateurs public, protected et private.
 On peut ainsi retrouver au niveau des classes internes certains
bénéfices de l'encapsulation.
 Si l'on combine plusieurs niveaux d'imbrication (qui créent une
hiérarchie de confinement) avec une hiérarchie de classes complexe,
on peut très vite arriver à de grandes complications en terme de
portée, visibilité et masquage des identificateurs concernés.
 Les classes internes ne doivent être utilisées que si elles apportent
des simplifications dans la conception et favorisent la lisibilité et la
maintenance du code. Sinon, elles sont plutôt à éviter.
EIA-FR / Jacques Bapst
PR1_14
17
Java / Classes internes
Remarques sur les classes internes [2]
 Dans les applications comportant une interface utilisateur
graphique (GUI), les classes internes et plus particulièrement les
classes anonymes sont fréquemment utilisées pour créer, à
la volée, des gestionnaires d'événements (Event Listener).
 Sur le plan de l'implémentation, les classes internes sont traitées
de la même manière que les classes de premier niveau : chacune
donne lieu à un fichier .class séparé (c'est également vrai pour les
classes anonymes).
 Suivant les types de classes internes, le nom du fichier résultant
de la compilation est composé de manière différente mais il
comporte généralement le caractère '$' (on trouvera par exemple les
fichiers LinkedStack$Linkable.class ou FilenameFilter$1.class).
 Lors du déploiement d'une application, il peut être important de
connaître ces détails d'implémentation; par contre, pour l'écriture
d'une application, cela n'a aucune incidence.
EIA-FR / Jacques Bapst
PR1_14
18
Téléchargement