Classes locales en Java
Déclarez des classes à l'intérieur de corps de méthodes en Java avec les classes locales, avec accès aux variables locales effectivement finales.
Une classe locale est une classe déclarée à l'intérieur du corps d'une méthode (ou d'un constructeur, ou d'un bloc d'initialisation). Sa portée se limite au bloc dans lequel elle est déclarée — rien en dehors de ce bloc ne peut la désigner par son nom. Par ailleurs, elle se comporte comme une classe interne, avec accès aux membres de l'instance englobante et aux variables locales effectivement finales de la méthode.
Les classes locales sont rares en Java moderne. Les lambdas ont remplacé leurs principaux cas d'usage pour les rappels à une seule méthode, et les classes anonymes sont généralement plus concises pour les implémentations ponctuelles. Mais une classe locale est parfois la solution la plus claire lorsque vous avez besoin d'un type nommé qui participe à la logique de la méthode englobante et n'est utile nulle part ailleurs.
Si vous n'avez pas encore rencontré les autres membres de la famille des classes imbriquées, les chapitres vue d'ensemble des classes imbriquées et classes internes établissent les termes utilisés ci-dessous.
Déclarer une classe locale
Une déclaration de classe placée à l'intérieur d'un corps de méthode :
public void process(List<String> lines) {
class Counter {
int n = 0;
void inc() { n++; }
}
Counter c = new Counter();
for (String s : lines) if (!s.isBlank()) c.inc();
System.out.println("non-blank lines: " + c.n);
}En dehors de process, personne ne peut voir Counter — son nom n'existe pas au-delà de l'accolade fermante de la méthode. À l'intérieur, vous l'utilisez comme n'importe quelle autre classe.
Pourquoi la choisir plutôt qu'une classe anonyme ?
Une classe locale possède un vrai nom, ce qui vous offre quelques avantages qu'une classe anonyme ne peut pas avoir :
- Un constructeur. Vous pouvez lui donner des paramètres, écrire des validations et avoir plusieurs constructeurs.
- Plusieurs instances. Comme la classe a un nom, vous pouvez écrire
new Counter()plus d'une fois. La définition d'une classe anonyme ne crée qu'une seule instance par expression. - Auto-référence.
Counterpeut se prendre elle-même en paramètre, détenir un champCounter next, récurser — tout ce que les types nommés peuvent faire. - Lisibilité. Un nom comme
Counterdocumente le rôle du helper. Les blocs anonymesnew Object() { ... }sont plus difficiles à parcourir rapidement.
Accès à l'état englobant
Les classes locales peuvent :
- Lire et écrire les champs de l'instance englobante (si la méthode englobante est non statique).
- Appeler les méthodes d'instance de la classe englobante.
- Lire — mais pas réaffecter — les variables locales et les paramètres final ou effectivement final de la méthode englobante.
void run(int multiplier) {
class Scaler {
int scale(int x) { return x * multiplier; } // captures the parameter
}
System.out.println(new Scaler().scale(7));
}multiplier est capturé dans la classe synthétique sous forme de champ. C'est la raison de l'exigence « effectivement final » — si multiplier pouvait être réaffecté dans run après que Scaler eût capturé son ancienne valeur, les deux seraient silencieusement en désaccord.
Dans une méthode statique
Dans une méthode static, la classe locale est implicitement statique — elle n'a pas d'instance englobante à laquelle faire référence :
public static int demo() {
class Helper {
int square(int n) { return n * n; }
}
return new Helper().square(7);
}Il n'y a pas de Outer.this ici, car la méthode englobante est statique. Helper peut toujours capturer des variables locales effectivement finales de demo, mais pas les champs d'instance d'un objet englobant qui n'existe pas.
Quand en utiliser une concrètement
Cas concrets où une classe locale surpasse réellement les alternatives :
- Le helper a plus d'une méthode, et vous préférez voir les méthodes regroupées avec un nom clair plutôt que dispersées dans du code passe-partout de classe anonyme.
- Le helper a besoin d'un constructeur pour valider sa configuration.
- Le helper récurse ou contient des références à d'autres instances de son propre type.
Si un lambda ou une courte classe anonyme suffit, préférez cela. Les classes locales sont un outil de niche.
Modificateurs
Une classe locale accepte uniquement un ensemble restreint de modificateurs :
final— marque la classe comme non extensible. Elle n'a déjà pas de nom accessible au code extérieur pour être étendue, donc c'est principalement une déclaration d'intention.abstract— légal mais rare : vous auriez besoin d'une deuxième classe locale dans le même bloc pour l'étendre.- Les modificateurs d'accès (
public,protected,private) ne sont pas autorisés. Une classe locale vit entièrement à l'intérieur d'un seul bloc, donc il n'existe aucune portée extérieure à ce bloc depuis laquelle la visibilité pourrait être contrôlée.
Elle ne peut pas non plus être déclarée static directement. Le fait qu'elle capture ou non une instance englobante dépend de si la méthode environnante est statique, comme montré ci-dessus — pas d'un mot-clé.
Un exemple concret
La suite
Cela conclut la présentation des classes imbriquées — et la majeure partie de la mécanique OOP classique de Java. La prochaine section de la Partie 6 aborde les types de classes spéciaux : les types que Java fournit pour des formes de données spécifiques, en commençant par enum pour les ensembles fixes de constantes. Continuez vers les enums Java.