class OuterClass {
...
static class StaticNestedClass {
...
}
class InnerClass {
...
}
}
Ces classes internes sont dites imbriquées. Ils sont divisés en 2 types :
- Classes imbriquées non statiques. Celles-ci sont également appelées classes internes.
- Classes imbriquées statiques.
- une classe locale
- une classe anonyme

public class Bicycle {
private String model;
private int weight;
public Bicycle(String model, int weight) {
this.model = model;
this.weight = weight;
}
public void start() {
System.out.println("Let's go!");
}
public class Handlebar {
public void right() {
System.out.println("Steer right!");
}
public void left() {
System.out.println("Steer left!");
}
}
public class Seat {
public void up() {
System.out.println("Seat up!");
}
public void down() {
System.out.println("Seat down!");
}
}
}
Ici, nous avons la Bicycle
classe. Il a 2 champs et 1 méthode : start()
. 
Handlebar
et Seat
. Leur code est écrit à l'intérieur de la Bicycle
classe. Ce sont des classes à part entière : comme vous pouvez le voir, chacune d'elles a ses propres méthodes. À ce stade, vous pourriez avoir une question : pourquoi diable devrions-nous mettre une classe à l'intérieur d'une autre ? Pourquoi en faire des classes internes ? Eh bien, supposons que nous ayons besoin de classes distinctes pour les concepts de guidon et de siège dans notre programme. Bien entendu, il ne nous est pas nécessaire de les imbriquer ! Nous pouvons faire des cours ordinaires. Par exemple, comme ceci :
public class Handlebar {
public void right() {
System.out.println("Steer right!");
}
public void left() {
System.out.println("Steer left");
}
}
public class Seat {
public void up() {
System.out.println("Seat up!");
}
public void down() {
System.out.println("Seat down!");
}
}
Très bonne question ! Bien sûr, nous ne sommes pas limités par la technologie. Faire cela est certainement une option. Ici, l'important est davantage la conception correcte des classes du point de vue d'un programme spécifique et de son objectif. Les classes internes servent à séparer une entité qui est inextricablement connectée à une autre entité. Les guidons, les sièges et les pédales sont des composants d'un vélo. Séparés du vélo, ils n'ont pas beaucoup de sens. Si nous avions fait de tous ces concepts des classes publiques séparées, nous aurions eu le code comme celui-ci dans notre programme :
public class Main {
public static void main(String[] args) {
Handlebar handlebar = new Handlebar();
handlebar.right();
}
}
Hmm... La signification de ce code est même difficile à expliquer. Nous avons un guidon vague (Pourquoi est-ce nécessaire ? Aucune idée, pour être honnête). Et cette poignée tourne à droite... toute seule, sans vélo... pour une raison quelconque. En séparant le concept du guidon du concept du vélo, nous avons perdu un peu de logique dans notre programme. En utilisant une classe interne, le code est très différent :
public class Main {
public static void main(String[] args) {
Bicycle peugeot = new Bicycle("Peugeot", 120);
Bicycle.Handlebar handlebar = peugeot.new Handlebar();
Bicycle.Seat seat = peugeot.new Seat();
seat.up();
peugeot.start();
handlebar.left();
handlebar.right();
}
}
Sortie console :
Seat up!
Let's go!
Steer left!
Steer right!
Maintenant, ce que nous voyons prend tout à coup un sens ! :) Nous avons créé un objet vélo. Nous avons créé deux "sous-objets" de vélo : un guidon et un siège. Nous avons relevé la selle pour plus de confort et c'est parti : pédalage et direction au besoin ! :) Les méthodes dont nous avons besoin sont appelées sur les objets appropriés. Tout est simple et pratique. Dans cet exemple, la séparation du guidon et de la selle améliore l'encapsulation (nous cachons les données sur les pièces du vélo dans la classe concernée) et nous permet de créer une abstraction plus détaillée. Examinons maintenant une situation différente. Supposons que nous voulions créer un programme qui simule un magasin de vélos et des pièces détachées pour vélos. 
-
Un objet d'une classe interne ne peut exister sans un objet d'une classe externe.
Cela a du sens : c'est pourquoi nous avons créé les classes
Seat
etHandlebar
internes dans notre programme - afin de ne pas nous retrouver avec des guidons et des sièges orphelins.Ce code ne compile pas :
public static void main(String[] args) { Handlebar handlebar = new Handlebar(); }
Une autre caractéristique importante en découle :
-
Un objet d'une classe interne a accès aux variables de la classe externe.
Par exemple, ajoutons une
int seatPostDiameter
variable (représentant le diamètre de la tige de selle) à notreBicycle
classe.Ensuite, dans la
Seat
classe interne, nous pouvons créer unedisplaySeatProperties()
méthode qui affiche les propriétés du siège :public class Bicycle { private String model; private int weight; private int seatPostDiameter; public Bicycle(String model, int weight, int seatPostDiameter) { this.model = model; this.weight = weight; this.seatPostDiameter = seatPostDiameter; } public void start() { System.out.println("Let's go!"); } public class Seat { public void up() { System.out.println("Seat up!"); } public void down() { System.out.println("Seat down!"); } public void displaySeatProperties() { System.out.println("Seat properties: seatpost diameter = " + Bicycle.this.seatPostDiameter); } } }
Et maintenant nous pouvons afficher ces informations dans notre programme :
public class Main { public static void main(String[] args) { Bicycle bicycle = new Bicycle("Peugeot", 120, 40); Bicycle.Seat seat = bicycle.new Seat(); seat.displaySeatProperties(); } }
Sortie console :
Seat properties: seatpost diameter = 40
Note:la nouvelle variable est déclarée avec le modificateur d'accès le plus strict (
private
). Et toujours la classe intérieure a accès ! -
Un objet d'une classe interne ne peut pas être créé dans une méthode statique d'une classe externe.
Cela s'explique par les spécificités de l'organisation des classes internes. Une classe interne peut avoir des constructeurs avec des paramètres, ou simplement le constructeur par défaut. Mais quoi qu'il en soit, lorsque nous créons un objet d'une classe interne, une référence à l'objet de la classe externe est transmise de manière invisible à l'objet créé de la classe interne. Après tout, la présence d'une telle référence d'objet est une exigence absolue. Sinon, nous ne pourrons pas créer d'objets de la classe interne.
Mais si une méthode de la classe externe est statique, alors nous pourrions ne pas avoir d'objet de la classe externe ! Et ce serait une violation de la logique de fonctionnement d'une classe interne. Dans cette situation, le compilateur générera une erreur :
public static Seat createSeat() { // Bicycle.this cannot be referenced from a static context return new Seat(); }
-
Une classe interne ne peut pas contenir de variables et de méthodes statiques.
La logique est la même : des méthodes et des variables statiques peuvent exister et être appelées ou référencées même en l'absence d'objet.
Mais sans objet de la classe externe, nous n'aurons pas accès à la classe interne.
Une contradiction évidente ! C'est pourquoi les variables et méthodes statiques ne sont pas autorisées dans les classes internes.
Le compilateur générera une erreur si vous essayez de les créer :
public class Bicycle { private int weight; public class Seat { // An inner class cannot have static declarations public static void displaySeatProperties() { System.out.println("Seat properties: seatpost diameter = " + Bicycle.this.seatPostDiameter); } } }
-
Lors de la création d'un objet d'une classe interne, son modificateur d'accès est important.
Une classe interne peut être marquée avec les modificateurs d'accès standard :
public
,private
,protected
etpackage private
.Pourquoi est-ce important ?
Cela affecte où nous pouvons créer des instances de la classe interne dans notre programme.
Si notre
Seat
classe est déclarée commepublic
, nous pouvons créerSeat
des objets dans n'importe quelle autre classe. La seule exigence est qu'un objet de la classe externe doit également exister.Au fait, nous l'avons déjà fait ici :
public class Main { public static void main(String[] args) { Bicycle peugeot = new Bicycle("Peugeot", 120); Bicycle.Handlebar handlebar = peugeot.new Handlebar(); Bicycle.Seat seat = peugeot.new Seat(); seat.up(); peugeot.start(); handlebar.left(); handlebar.right(); } }
Nous avons facilement eu accès à la
Handlebar
classe intérieure à partir de laMain
classe.Si nous déclarons la classe interne comme
private
, nous pourrons créer des objets uniquement à l'intérieur de la classe externe.On ne peut plus créer d'
Seat
objet "à l'extérieur" :private class Seat { // Methods } public class Main { public static void main(String[] args) { Bicycle bicycle = new Bicycle("Peugeot", 120, 40); // Bicycle.Seat has private access in Bicycle Bicycle.Seat seat = bicycle.new Seat(); } }
Vous comprenez probablement déjà la logique :)
-
Les modificateurs d'accès pour les classes internes fonctionnent de la même manière que pour les variables ordinaires.
Le
protected
modificateur donne accès à une variable d'instance dans les sous-classes et les classes qui se trouvent dans le même package.protected
fonctionne également pour les classes internes. Nous pouvons créerprotected
des objets de la classe interne :- dans la classe extérieure;
- dans ses sous-classes ;
- dans les classes qui sont dans le même package.
Si la classe interne n'a pas de modificateur d'accès (
package private
), les objets de la classe interne peuvent être créés :- dans la classe extérieure;
- dans les classes qui sont dans le même package.
Vous connaissez les modificateurs depuis longtemps, donc pas de problème ici.
GO TO FULL VERSION