Lorsque des classes internes ont été ajoutées à Java dans la version 1.1 du langage, elles ont été initialement définies comme une transformation en code compatible 1.0. Si vous regardez un exemple de cette transformation, je pense que cela rendra beaucoup plus clair comment une classe interne fonctionne réellement.
Considérez le code de la réponse d'Ian Roberts:
public class Foo {
int val;
public Foo(int v) { val = v; }
class Bar {
public void printVal() {
System.out.println(val);
}
}
public Bar createBar() {
return new Bar();
}
}
Une fois transformée en code compatible 1.0, cette classe interne Bardeviendrait quelque chose comme ceci:
class Foo$Bar {
private Foo this$0;
Foo$Bar(Foo outerThis) {
this.this$0 = outerThis;
}
public void printVal() {
System.out.println(this$0.val);
}
}
Le nom de la classe interne est précédé du nom de la classe externe afin de le rendre unique. Un this$0membre privé masqué est ajouté qui contient une copie de l'externe this. Et un constructeur caché est créé pour initialiser ce membre.
Et si vous regardez la createBarméthode, elle serait transformée en quelque chose comme ceci:
public Foo$Bar createBar() {
return new Foo$Bar(this);
}
Voyons donc ce qui se passe lorsque vous exécutez le code suivant.
Foo f = new Foo(5);
Foo.Bar b = f.createBar();
b.printVal();
Tout d'abord, nous instancions une instance de Fooet initialisons le valmembre à 5 (ie f.val = 5).
Ensuite, nous appelons f.createBar(), qui instancie une instance de Foo$Baret initialise le this$0membre à la valeur de thispassé de createBar(ie b.this$0 = f).
Enfin, nous appelons b.printVal()qui essaie d'imprimer b.this$0.valce f.valqui vaut 5.
Maintenant, c'était une instanciation régulière d'une classe interne. Regardons ce qui se passe lors de l'instanciation Barde l'extérieur Foo.
Foo f = new Foo(5);
Foo.Bar b = f.new Bar();
b.printVal();
En appliquant à nouveau notre transformation 1.0, cette deuxième ligne deviendrait quelque chose comme ceci:
Foo$Bar b = new Foo$Bar(f);
C'est presque identique à l' f.createBar()appel. Encore une fois, nous instancions une instance de Foo$Baret initialisons le this$0membre à f. Encore une fois, b.this$0 = f.
Et encore une fois, lorsque vous appelez b.printVal(), vous imprimez b.thi$0.valce f.valqui est de 5.
La chose clé à retenir est que la classe interne a un membre masqué contenant une copie de thisde la classe externe. Lorsque vous instanciez une classe interne à partir de la classe externe, elle s'est implicitement initialisée avec la valeur actuelle de this. Lorsque vous instanciez la classe interne depuis l'extérieur de la classe externe, vous spécifiez explicitement l'instance de la classe externe à utiliser, via le préfixe du newmot - clé.