1. Classe imbriquée statique
Une classe imbriquée statique (static nested class) est une classe déclarée à l’intérieur d’une autre classe avec le modificateur static. En substance, c’est une classe ordinaire qui « vit » à l’intérieur d’une autre classe, mais qui n’est pas liée à son objet.
Si une classe interne est comme un petit frère qui tient toujours la main de l’aîné (l’objet de la classe externe), alors une classe imbriquée statique est un cousin qui ne vient qu’aux fêtes de famille et vit sa propre vie le reste du temps.
Différences clés :
- Pas de référence implicite à l’objet de la classe externe — pas de OuterClass.this ni d’accès aux membres non statiques.
- Peut contenir des membres statiques (contrairement à une classe interne ordinaire).
- Se crée sans objet de la classe externe.
Syntaxe de déclaration
Déclarer une classe imbriquée statique est très simple : on utilise le mot-clé static à l’intérieur de la classe externe.
class Outer {
static class Nested {
void print() {
System.out.println("Hello from Nested!");
}
}
}
Et c’est tout ! Pas de constructions syntaxiques tordues — juste static class.
Visualisation :
Outer (classe externe)
│
├── Nested (classe imbriquée statique)
│ └── print()
2. Création d’une instance d’une classe imbriquée statique
Le plus agréable : aucun objet de la classe externe n’est nécessaire !
Outer.Nested nested = new Outer.Nested();
nested.print(); // Hello from Nested!
Notez que nous utilisons le nom complet de la classe — Outer.Nested. C’est comme s’adresser à la classe imbriquée par le nom de famille : « Smith.Fils ».
Comparez avec une classe interne (inner) :
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner(); // nécessite un objet outer
Pour une static nested class, l’objet Outer n’est tout simplement pas nécessaire !
3. Accès aux membres de la classe externe
Voici la différence principale avec une classe interne.
- Une classe imbriquée statique n’a accès QU’aux membres statiques de la classe externe.
- Il est impossible d’accéder aux champs et méthodes non statiques (même s’ils sont public).
Exemple :
class Outer {
private static int staticValue = 10;
private int instanceValue = 20;
static class Nested {
void show() {
System.out.println("Static value: " + staticValue); // OK
// System.out.println("Instance value: " + instanceValue); // Erreur !
}
}
}
Si vous essayez d’accéder au champ non statique instanceValue, le compilateur vous fera aussitôt la leçon.
Pourquoi ? Parce qu’une static nested class ne « sait » pas à quel objet Outer elle doit être liée — elle ne possède pas de référence à l’objet de la classe externe.
4. Quand utiliser des classes imbriquées statiques
Quand sont-elles appropriées ?
- Quand la classe imbriquée est logiquement liée à la classe externe, mais n’a pas besoin d’accéder à l’objet de la classe externe.
- Quand vous souhaitez encapsuler une structure auxiliaire : par exemple, un builder, un utilitaire, une énumération ou même un petit objet immuable.
- Quand vous voulez réduire l’« encombrement » du package : la classe n’est nécessaire qu’à la classe externe, inutile de la sortir.
Scénarios typiques :
- Patron Builder (surtout pour les objets immuables)
- Implémentation de structures auxiliaires : par exemple, des classes Node internes dans des collections
- Regroupement de constantes ou d’utilitaires
Règle simple de choix
Posez-vous la question : « Mon classe imbriquée a-t-elle besoin d’accéder à un objet concret de la classe externe ? »
NON → utilisez une static class (classe imbriquée statique)
OUI → utilisez une class ordinaire (interne)
5. Exemples d’utilisation
Exemple 1 : Builder pour une classe
Supposons que nous avons une classe Person, et que nous voulons implémenter pour elle le patron Builder :
public class Person {
private final String name;
private final int age;
// Constructeur privé
private Person(Builder builder) {
this.name = builder.name;
this.age = builder.age;
}
// Classe imbriquée statique Builder
public static class Builder {
private String name;
private int age;
public Builder setName(String name) {
this.name = name;
return this;
}
public Builder setAge(int age) {
this.age = age;
return this;
}
public Person build() {
return new Person(this);
}
}
public void printInfo() {
System.out.println("Person: " + name + ", " + age);
}
}
Utilisation :
Person person = new Person.Builder()
.setName("John")
.setAge(30)
.build();
person.printInfo(); // Person: John, 30
Pourquoi Builder est-il une classe imbriquée statique ?
Parce qu’il ne dépend pas de l’objet Person, il aide seulement à le créer. Il est logiquement lié à Person, mais pas à une instance concrète.
Exemple 2 : Structure auxiliaire dans une collection
Imaginons une classe « boîte de nombres », où un Node interne statique est utilisé pour stocker les éléments :
public class IntBox {
private Node head;
// Classe statique imbriquée
private static class Node {
int value;
Node next;
Node(int value) {
this.value = value;
}
}
public void add(int value) {
Node node = new Node(value);
node.next = head;
head = node;
}
public void printAll() {
Node current = head;
while (current != null) {
System.out.println(current.value);
current = current.next;
}
}
}
Utilisation :
IntBox box = new IntBox();
box.add(1);
box.add(2);
box.add(3);
box.printAll(); // 3 2 1
Pourquoi Node est-il static ?
Parce que chaque Node n’a pas besoin de connaître toute la boîte (IntBox) ; il stocke simplement des données et une référence vers le Node suivant.
Exemple 3 : Classe utilitaire à l’intérieur de la principale
public class MathUtils {
// Classe imbriquée statique pour travailler avec les nombres complexes
public static class Complex {
private final double re;
private final double im;
public Complex(double re, double im) {
this.re = re;
this.im = im;
}
public Complex add(Complex other) {
return new Complex(this.re + other.re, this.im + other.im);
}
@Override
public String toString() {
return re + " + " + im + "i";
}
}
}
Utilisation :
MathUtils.Complex a = new MathUtils.Complex(1, 2);
MathUtils.Complex b = new MathUtils.Complex(3, 4);
MathUtils.Complex sum = a.add(b);
System.out.println(sum); // 4.0 + 6.0i
6. Points utiles
Classe interne vs classe imbriquée statique
| Classe interne (inner) | Classe imbriquée statique (static nested) | |
|---|---|---|
| Mot-clé | aucun | |
| Référence implicite à l’objet externe | oui | non |
| Accès aux membres non statiques de la classe externe | oui | non |
| Accès aux membres statiques de la classe externe | oui | oui |
| Peut contenir des membres statiques | non (seulement des constantes) | oui |
| Syntaxe de création | |
|
| Utilisation | Quand l’accès à l’objet de la classe externe est nécessaire | Quand l’accès à l’objet de la classe externe n’est pas nécessaire |
Illustration
flowchart LR
OuterClass -->|has| InnerClass
OuterClass -.->|has| StaticNestedClass
StaticNestedClass -.->|can access| staticMembers
InnerClass -->|can access| instanceMembers
InnerClass -->|can access| staticMembers
Particularités et limites
- Une static nested class peut contenir des champs et méthodes ordinaires comme statiques.
- Elle peut être déclarée avec n’importe quel modificateur d’accès (public, private, protected, package-private).
- Elle peut implémenter des interfaces et hériter d’autres classes.
- Elle peut être generic.
- Elle est généralement utilisée pour encapsuler des classes utilitaires qui ne sont pas nécessaires en dehors de la classe externe.
Exemple de generic static nested class :
public class Box {
public static class Holder<T> {
private T value;
public Holder(T value) { this.value = value; }
public T get() { return value; }
}
}
Quand il NE faut PAS utiliser une static nested class
- Si la classe imbriquée a besoin d’accéder aux champs/méthodes non statiques de la classe externe — utilisez une classe interne ordinaire.
- Si la classe est nécessaire en dehors de la classe externe — mettez-la dans un fichier séparé.
- Si la classe est trop grande ou complexe — mieux vaut en faire une classe séparée.
7. Erreurs typiques et nuances
Erreur n°1 : Confusion entre classe interne et classe imbriquée statique.
Beaucoup de débutants essaient, dans une static nested class, d’accéder aux champs non statiques de la classe externe. Mais une static nested class n’a pas de référence à l’objet de la classe externe, c’est donc impossible. Si vous avez besoin d’accéder à l’état d’un objet concret — utilisez une classe interne ordinaire.
Erreur n°2 : Tentative de créer une static nested class via un objet de la classe externe.
Il est inutile d’écrire outer.new Inner(). Pour une static nested class, utilisez toujours new Outer.Nested().
Erreur n°3 : Utiliser une static nested class pour une logique nécessitant l’accès à l’instance de la classe externe.
Si la logique de la classe est étroitement liée à l’état de l’objet de la classe externe, la static nested class est un mauvais choix. Utilisez une classe interne ordinaire.
Erreur n°4 : Imbrication trop complexe.
N’abusez pas des classes imbriquées. Si la structure devient confuse, il vaut mieux extraire certaines classes.
GO TO FULL VERSION