Méthode classe interne interne vs classe interne

Le code ci-dessous produit le middle sortie. Quelqu’un peut-il expliquer en détail comment cela se passe?

Est-ce parce que la déclaration de la version “interne” de la class A intervient après la création de l’instance de la class A dans la méthode go() ?

 class A { void m() { System.out.println("outer"); } } public class MethodLocalVSInner { public static void main(Ssortingng[] args) { new MethodLocalVSInner().go(); } void go() { new A().m(); class A { void m() { System.out.println("inner"); } } } class A { void m() { System.out.println("middle"); } } } 

Je suppose que vous vous attendiez à ce que la méthode de classe locale soit invoquée. Cela ne s’est pas produit, car vous utilisez new A() dehors de la classe locale. Ainsi, il accède au candidat le plus proche dans la scope, qui serait la classe interne. De JLS §6.3 :

La scope d’une déclaration de classe locale immédiatement entourée d’un bloc (§14.2) est le rest du bloc immédiatement englobant, y compris sa propre déclaration de classe.

Ainsi, new A() dans la première ligne de la méthode, n’accédera pas à la classe locale apparaissant après. Si vous déplacez la déclaration de classe avant cela, vous obtiendrez la sortie attendue.

Voir également le § 14.3 de JLS , qui contient un exemple similaire.

Vous obtenez la sortie “middle” en raison de l’ordre dans lequel vous avez votre code. Puisque la class A la méthode se produit après votre appel au new A() , vous obtenez la sortie “middle”. Si vous changez l’ordre comme suit, vous obtiendrez le résultat “inner”:

 void go() { class A { void m() { System.out.println("inner"); } } new A().m(); } 

Sortie:

inner

L’ordre de priorité pour l’instanciation de la class A , de haut en bas, est le suivant:

  1. bloc
  2. méthode
  3. classe
  4. paquet

S’il vous plaît jeter un oeil à la spécification Java Language officielle discuter des classes internes pour plus d’informations.

La raison pour laquelle l’ inner n’est pas imprimé est ( 6.3 ):

La scope d’une déclaration de classe locale immédiatement entourée d’un bloc est le rest du bloc immédiatement englobant, y compris sa propre déclaration de classe.

(Une classe déclarée dans une méthode est appelée classe locale.)

Donc, A ne peut pas faire référence à la classe locale, car l’expression new A() se produit avant sa déclaration. En d’autres termes, les classes locales ont une scope similaire aux variables locales.

La raison pour laquelle le middle est imprimé au lieu de la partie outer est que la classe interne A ombrage la classe de niveau supérieur A ( 6.4.1 ):

Une déclaration d d’un type nommé n masque les déclarations de tout autre type nommé n qui sont dans la scope […] de d .

Cela signifie que n’importe où dans le corps de MethodLocalVSInner , le non qualifié doit faire référence à la classe interne.

Si vous êtes familier avec l’observation des variables membres, par exemple:

 class Example { int x; void setX(int x) { // ┌ 'x' refers to the local method parameter this.x = x; } } 

La même chose se passe essentiellement avec les déclarations de classe.

Cas 1:

 void go() { new A().m(); class A { void m() { System.out.println("inner"); } } } 

Dans ce cas, si vous exécutez votre méthode en dehors du champ d’application de la classe locale. C’est pourquoi il va imprimer au middle

Cas 2:

 void go() { class A { void m() { System.out.println("inner"); } } new A().m(); } 

Dans ce cas, il imprimera en inner parce que la classe est maintenant dans la scope.

en méthode:

  void go() { new A().m(); class A { void m() { System.out.println("inner"); } } } 

lorsque la méthode est lancée, la première ligne sera exécutée new A().m();

et parce que la classe interne est déjà dans la scope, l’object pour cette classe sera créé et la méthode m sera appelée pour inner class pas pour local method class car elle n’est toujours pas dans la scope. c’est pour cela que vous obtenez un rendement middle .

mais si vous modifiez votre méthode comme:

  void go() { class A { void m() { System.out.println("inner"); } } new A().m(); } 

Votre classe de méthode locale sera désormais dans la scope et aura une préférence plus élevée afin que vous ayez désormais une sortie inner .

Vous appelez la méthode go utilisant une instance de MethodLocalVSInner

Dans la méthode go, vous créez une instance de A() car vous n’importez pas explicitement la A class externe A class et la classe interne immédiate après l’instruction de la méthode, JVM sélectionne la inner class A qui est au niveau de la classe de MethodLocalVSInner et exécuter la méthode go à l’intérieur de