1. Classe locale
Une classe locale est une classe déclarée à l’intérieur d’une méthode (ou même d’un bloc de code, par exemple dans une boucle ou un bloc if). Elle est visible et accessible uniquement dans cette méthode ; en dehors — c’est comme si elle n’existait pas. Contrairement aux classes anonymes, une classe locale a un nom (même simple), peut contenir plusieurs méthodes et même des champs.
Par analogie — imaginez que vous préparez un plat complexe selon une recette. À l’une des étapes, vous devez préparer une sauce spéciale, utilisée uniquement dans cette recette et nulle part ailleurs. Au lieu de publier un livre de recettes séparé pour une seule sauce, vous décrivez simplement sa préparation directement dans la recette principale. Une classe locale fonctionne de la même manière — c’est « une recette dans la recette », nécessaire uniquement dans une méthode précise.
Exemple de déclaration d’une classe locale
public class Outer {
void someMethod() {
class Local {
void print() {
System.out.println("Hello from Local!");
}
}
Local local = new Local();
local.print();
}
}
Ici, la classe Local est déclarée à l’intérieur de la méthode someMethod de la classe Outer. Elle n’existe que dans cette méthode et n’est pas visible de l’extérieur.
Syntaxe des classes locales
La déclaration d’une classe locale ressemble à une déclaration de classe ordinaire, sauf qu’elle a lieu à l’intérieur d’une méthode :
void myMethod() {
class MyLocalClass {
void doSomething() {
System.out.println("La classe locale fonctionne!");
}
}
MyLocalClass obj = new MyLocalClass();
obj.doSomething();
}
Particularités de la syntaxe :
- Une classe locale peut être déclarée dans n’importe quelle méthode, constructeur ou même bloc d’initialisation.
- Le nom d’une classe locale est obligatoire (contrairement aux classes anonymes).
- Une classe locale ne peut pas être déclarée avec des modificateurs d’accès (public, private, protected) ni avec le modificateur static.
- Une classe locale peut implémenter des interfaces ou hériter d’autres classes.
Comparaison des types de classes :
public class Example {
// 1. Classe ordinaire (dans un fichier distinct)
// class RegularClass { ... }
// 2. Classe interne (dans une classe)
class InnerClass { }
// 3. Classe imbriquée statique (dans une classe)
static class NestedClass { }
void method() {
// 4. Classe locale (dans une méthode)
class LocalClass { }
// 5. Classe anonyme (dans une méthode, sans nom)
Object obj = new Object() { };
}
}
Classe locale = une classe nommée réservée à cette méthode !
2. Particularités des classes locales
Accès aux variables de la méthode
Une classe locale peut accéder :
- Aux champs de la classe englobante (même s’ils sont private).
- Uniquement aux variables final ou effectively final de la méthode environnante.
Qu’est-ce que « effectively final » ?
C’est une variable dont la valeur ne change pas après son initialisation. Par exemple :
void foo() {
int x = 5; // effectively final
class L { void print() { System.out.println(x); } }
}
Si, plus tard, vous écriviez x = 10;, le compilateur se plaindrait.
Pourquoi ?
Cela tient à la manière dont Java implémente les classes locales « sous le capot » : les variables de la méthode sont en fait copiées dans la classe locale, et non stockées par référence. Si la variable pouvait changer, la classe locale pourrait travailler avec une copie obsolète — et c’est la voie vers des bugs et des maux de tête.
Exemple d’accès aux variables
public class Outer {
private String secret = "secret!";
void revealSecret() {
String greeting = "Bonjour,"; // effectively final
class Revealer {
void printSecret() {
System.out.println(greeting + " " + secret);
}
}
Revealer revealer = new Revealer();
revealer.printSecret();
}
}
3. Utilisation des classes locales : pourquoi et quand ?
Les classes locales ne sont pas un outil du quotidien, mais elles rendent parfois le code plus clair et plus compact. Voici quand il vaut la peine de les utiliser :
- Logique auxiliaire, spécifique à une seule méthode.
Par exemple, si vous devez implémenter dans une méthode un tri complexe, un filtrage ou une structure de données temporaire. - Encapsulation, pour ne pas « polluer » la classe avec des types superflus.
Si une classe n’est utile qu’à un seul endroit, pourquoi la rendre visible dans toute la classe ou le package ? - Mise en œuvre de patrons de conception, lorsque des objets auxiliaires ne sont nécessaires que localement.
Exemple : trier avec une classe locale
Supposons que vous ayez une liste de noms et que vous souhaitiez les trier par longueur. Vous pouvez créer une classe locale comparatrice :
import java.util.*;
public class NameSorter {
public void sortNames(List<String> names) {
class LengthComparator implements Comparator<String> {
@Override
public int compare(String a, String b) {
return Integer.compare(a.length(), b.length());
}
}
Collections.sort(names, new LengthComparator());
}
}
Exemple : structure temporaire
Parfois, vous devez créer une structure auxiliaire pour traiter des données dans une seule méthode :
void processScores(int[] scores) {
class ScoreInfo {
int score;
boolean passed;
ScoreInfo(int score) {
this.score = score;
this.passed = score >= 60;
}
}
for (int s : scores) {
ScoreInfo info = new ScoreInfo(s);
System.out.println("Note: " + info.score + ", réussi: " + info.passed);
}
}
4. Classes locales vs classes anonymes
On se demande parfois : à quoi servent les classes locales s’il existe des classes anonymes ? Voyons cela.
- Classe locale — une classe nommée que l’on peut réutiliser plusieurs fois dans la méthode, à laquelle on peut ajouter des champs, plusieurs méthodes, des classes imbriquées.
- Classe anonyme — une implémentation ponctuelle d’une interface ou d’un héritier, sans nom, généralement avec une seule méthode (ou la redéfinition d’une ou deux méthodes).
Quand les utiliser :
- Si la logique est simple et requise une seule fois — utilisez une classe anonyme.
- Si vous avez besoin de plusieurs méthodes ou champs, ou si la classe sera utilisée à plusieurs endroits de la méthode — utilisez une classe locale.
Exemple de comparaison
Classe anonyme :
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println("Rapide et anonyme!");
}
};
Classe locale :
void doWork() {
class MyWorker implements Runnable {
@Override
public void run() {
System.out.println("Je suis une classe locale!");
}
}
MyWorker worker = new MyWorker();
worker.run();
}
5. Limitations et particularités des classes locales
- Modificateurs d’accès : Une classe locale ne peut pas être déclarée public, private ou protected. Il est également impossible d’ajouter static.
- Membres statiques : Une classe locale ne peut pas contenir de membres statiques, à l’exception des constantes (static final).
- Périmètre de visibilité : Une classe locale n’est visible que dans le bloc où elle est déclarée.
- Paramètres génériques : Une classe locale peut être générique si nécessaire.
- Imbrication : Il est possible de déclarer des classes locales à l’intérieur d’autres classes locales (mais évitez d’en abuser, sinon le code finira par ressembler à une poupée russe).
6. Classes locales dans une application réelle
Poursuivons le développement de notre application d’apprentissage. Supposons que nous ayons une classe Quiz qui pose des questions à l’utilisateur et vérifie les réponses. Nous voulons, dans la méthode de vérification, créer une classe temporaire qui stockera la réponse de l’utilisateur et l’état de la vérification.
Exemple : utilisation d’une classe locale dans l’application
import java.util.Scanner;
public class Quiz {
private String question = "Capitale de la France ?";
private String correctAnswer = "Paris";
public void runQuiz() {
Scanner scanner = new Scanner(System.in);
System.out.println(question);
String userAnswer = scanner.nextLine();
// Classe locale pour stocker le résultat
class AnswerResult {
String answer;
boolean isCorrect;
AnswerResult(String answer) {
this.answer = answer;
this.isCorrect = answer.equalsIgnoreCase(correctAnswer);
}
void printResult() {
if (isCorrect) {
System.out.println("Correct!");
} else {
System.out.println("Incorrect, bonne réponse : " + correctAnswer);
}
}
}
AnswerResult result = new AnswerResult(userAnswer);
result.printResult();
}
}
Ici, la classe AnswerResult n’existe qu’à l’intérieur de la méthode runQuiz et n’est utile nulle part ailleurs. C’est un excellent exemple de classe locale en pratique !
7. Erreurs courantes avec les classes locales
Erreur n° 1 : tentative d’accès à une variable de méthode qui n’est pas final ou effectively final.
Si vous avez déclaré une variable dans une méthode et que vous en modifiez la valeur après l’avoir utilisée dans une classe locale, le compilateur signalera immédiatement une erreur. Assurez‑vous toujours que ces variables ne changent pas après l’initialisation.
Erreur n° 2 : vouloir ajouter des modificateurs d’accès ou static.
Une classe locale ne peut pas être déclarée avec les modificateurs public, private, protected ni avec static. Si vous essayez — le compilateur s’y opposera.
Erreur n° 3 : tenter d’utiliser une classe locale en dehors de la méthode.
Une classe locale ne vit que dans la méthode (ou le bloc) où elle est déclarée. Elle n’est pas accessible depuis d’autres méthodes ni depuis l’extérieur de la classe.
Erreur n° 4 : abuser des classes locales pour une logique complexe.
Si votre classe locale devient trop volumineuse, contient de nombreuses méthodes ou champs — il est probablement préférable de l’extraire dans une classe séparée. Les classes locales sont adaptées aux tâches compactes et auxiliaires.
GO TO FULL VERSION