El Tutoriel Java dit :
Terminologie : Les classes imbriquées sont divisées en deux catégories : statiques et non statiques. Les classes imbriquées qui déclarées statiques sont simplement appelées classes imbriquées statiques. Les classes imbriquées non statiques non statiques sont appelées inner classes.
Dans le langage courant, les termes "imbriqué" et "interne" sont utilisés de manière interchangeable par la plupart des programmeurs, mais j'utiliserai le terme correct de "classe imbriquée" qui couvre à la fois l'interne et le statique.
Les classes peuvent être imbriquées à l'infini Par exemple, la classe A peut contenir la classe B qui contient la classe C qui contient la classe D, etc. Toutefois, il est rare que les classes soient imbriquées sur plus d'un niveau, car elles sont généralement mal conçues.
Il y a trois raisons pour lesquelles vous pouvez créer une classe imbriquée :
- organisation : parfois, il semble plus judicieux de classer une classe dans l'espace de nom d'une autre classe, surtout lorsqu'elle ne sera pas utilisée dans un autre contexte.
- accès : les classes imbriquées ont un accès spécial aux variables/champs de leurs classes contenantes (précisément quelles variables/champs dépendent du type de classe imbriquée, interne ou statique).
- commodité : le fait de devoir créer un nouveau fichier pour chaque nouveau type est à nouveau gênant, surtout lorsque le type ne sera utilisé que dans un seul contexte.
Il y a quatre types de classes imbriquées en Java . En bref, il s'agit de :
-
classe statique déclaré comme membre statique d'une autre classe
-
classe intérieure : déclarée comme membre d'une autre classe
-
classe interne locale déclar déclar déclar déclar dans une méthode d'instance d'une autre classe
-
classe intérieure anonyme : comme une classe interne locale, mais écrite comme une expression qui renvoie un objet unique.
Permettez-moi de vous donner plus de détails.
Classes statiques
Les classes statiques sont les plus faciles à comprendre car elles n'ont rien à voir avec les instances de la classe qui les contient.
Une classe statique est une classe déclarée comme membre statique d'une autre classe. Tout comme les autres membres statiques, une telle classe n'est en fait qu'un accessoire qui utilise la classe qui la contient comme espace de nom, par exemple la classe Chèvre déclaré comme membre statique de la classe Rhino dans le paquet pizza est connu sous le nom de pizza.rhino.chèvre .
package pizza;
public class Rhino {
...
public static class Goat {
...
}
}
Franchement, les classes statiques sont une fonctionnalité plutôt inutile car les classes sont déjà divisées en espaces de noms par les paquets. La seule raison réellement concevable de créer une classe statique est qu'une telle classe a accès aux membres statiques privés de la classe qui la contient, mais je trouve que c'est une justification plutôt boiteuse pour l'existence de la fonctionnalité de classe statique.
Classes intérieures
Une classe interne est une classe déclarée comme membre non statique d'une autre classe :
package pizza;
public class Rhino {
public class Goat {
...
}
private void jerry() {
Goat g = new Goat();
}
}
Comme pour une classe statique, la classe interne est connue sous le nom de la classe qui la contient, pizza.rhino.chèvre mais dans la classe qui le contient, il peut être connu par son simple nom. Cependant, chaque instance d'une classe interne est liée à une instance particulière de sa classe contenante : ci-dessus, la classe Chèvre créé en jerry est implicitement liée à l Rhino instance este sur jerry . Sinon, nous faisons le Rhino explicite lorsque nous instancions Chèvre :
Rhino rhino = new Rhino();
Rhino.Goat goat = rhino.new Goat();
(Remarquez que vous vous référez au type interne comme juste Chèvre dans le bizarre nouveau syntaxe : Java déduit le type de contenu à partir du rhino partie. Et, oui nouveau rhino.Goat() aurait été plus logique pour moi aussi).
Alors, qu'est-ce que cela nous apporte ? Eh bien, l'instance de classe interne a accès aux membres d'instance de l'instance de classe contenante. Ces membres de l'instance englobante sont désignés à l'intérieur de la classe interne par les termes suivants via juste leurs simples noms, pas via este ( este dans la classe interne fait référence à l'instance de la classe interne, et non à l'instance de la classe contenante associée) :
public class Rhino {
private String barry;
public class Goat {
public void colin() {
System.out.println(barry);
}
}
}
Dans la classe interne, vous pouvez vous référer à este de la classe qui le contient comme Rhino.this et vous pouvez utiliser este pour désigner ses membres, par exemple, Rhino.this.barry .
Classes internes locales
Une classe interne locale est une classe déclarée dans le corps d'une méthode. Une telle classe n'est connue que dans la méthode qui la contient, elle ne peut donc être instanciée et ses membres ne sont accessibles que dans cette méthode. L'avantage est que l'instance d'une classe interne locale est liée aux variables locales finales de la méthode qui la contient et peut y accéder. Lorsque l'instance utilise une variable locale finale de la méthode qui la contient, la variable conserve la valeur qu'elle avait au moment de la création de l'instance, même si la variable est sortie de son champ d'application (il s'agit en fait de la version grossière et limitée des fermetures de Java).
Parce qu'une classe interne locale n'est pas membre d'une classe ou d'un package, elle n'est pas déclarée avec un niveau d'accès. (Il est clair, cependant, que ses propres membres ont des niveaux d'accès comme dans une classe normale).
Si une classe interne locale est déclarée dans une méthode d'instance, l'instanciation de la classe interne est liée à l'instance détenue par l'attribut este au moment de la création de l'instance, et donc les membres d'instance de la classe contenante sont accessibles comme dans une classe interne d'instance. Une classe interne locale est instanciée simplement via son nom, par exemple classe interne locale Chat est instancié en tant que nouveau Chat() et non pas new this.Cat() comme on pourrait s'y attendre.
Classes internes anonymes
Une classe interne anonyme est un moyen syntaxiquement pratique d'écrire une classe interne locale. Le plus souvent, une classe interne locale est instanciée au maximum une seule fois à chaque fois que la méthode qui la contient est exécutée. Il serait donc agréable de pouvoir combiner la définition de la classe interne locale et son instanciation unique en une seule forme syntaxique pratique, et il serait également agréable de ne pas avoir à trouver un nom pour la classe (moins votre code contient de noms inutiles, mieux c'est). Une classe interne anonyme permet ces deux choses :
new *ParentClassName*(*constructorArgs*) {*members*}
Il s'agit d'une expression renvoyant une nouvelle instance d'une classe non nommée qui prolonge Nom de la classe d'origine . Vous ne pouvez pas fournir votre propre constructeur ; au contraire, un constructeur est implicitement fourni qui appelle simplement le super constructeur, donc les arguments fournis doivent correspondre au super constructeur. (Si le parent contient plusieurs constructeurs, le plus "simple" est appelé, "le plus simple" étant déterminé par un ensemble de règles plutôt complexes qu'il ne vaut pas la peine d'apprendre en détail - faites simplement attention à ce que NetBeans ou Eclipse vous disent).
Vous pouvez également spécifier une interface à mettre en œuvre :
new *InterfaceName*() {*members*}
Une telle déclaration crée une nouvelle instance d'une classe non nommée qui étend Object et implémente Nom de l'interface . Encore une fois, vous ne pouvez pas fournir votre propre constructeur ; dans ce cas, Java fournit implicitement un constructeur sans argument et sans action (il n'y aura donc jamais d'arguments de constructeur dans ce cas).
Même si vous ne pouvez pas donner un constructeur à une classe interne anonyme, vous pouvez toujours faire tout ce que vous voulez en utilisant un bloc d'initialisation (un bloc {} placé en dehors de toute méthode).
Il est clair qu'une classe interne anonyme est simplement un moyen moins flexible de créer une classe interne locale avec une seule instance. Si vous voulez une classe interne locale qui implémente plusieurs interfaces ou qui implémente des interfaces tout en étendant une classe autre que la classe Objet ou qui spécifie son propre constructeur, vous êtes coincé en créant une classe interne locale nommée ordinaire.
91 votes
La réponse de Joshua Bloch est dans Java efficace lire
item 22 : Favor static member classes over non static
18 votes
Pour mémoire, il s'agit du point 24 de la 3e édition du même livre.