una que otra objeto nombre llevan internas interna interfaz interfaces estaticas ejemplos dentro crear clases clase anonimas java inner-classes

java - otra - que clases internas no llevan nombre



Método de clase interna local vs clase interna (6)

El siguiente código produce el middle salida. ¿Alguien puede explicar en detalle cómo está sucediendo esto?

¿Se debe a que la declaración de la versión "interna" de la class A produce después de que se crea la instancia de la class A en el método go() ?

class A { void m() { System.out.println("outer"); } } public class MethodLocalVSInner { public static void main(String[] 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"); } } }


Caso 1:

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

En este caso, si ejecuta su método fuera del alcance de la clase local. Por eso se imprimirá middle

Caso 2:

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

En este caso, se imprimirá inner clase becas inner ahora está en el ámbito.


Está llamando al método go utilizando una instancia de MethodLocalVSInner

Dentro del método go, está creando una instancia de A() aquí, ya que no importa explícitamente la A class externa y la clase interna inmediata se encuentra después de la instrucción de llamada al método, JVM está seleccionando la inner class A que se encuentra en el nivel de clase de MethodLocalVSInner y ejecuta el método go dentro de ese


Está obteniendo el resultado "medio" debido al orden en el que tiene su código. Dado que la class A con alcance de método se produce después de su llamada a la new A() , está obteniendo la salida "middle". Si cambia el orden de la siguiente manera, obtendrá la salida "interno":

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

Salida:

inner

El orden de prioridad para instanciar la class A , de alta a baja, es:

  1. bloquear
  2. método
  3. clase
  4. paquete

Por favor, eche un vistazo a la especificación oficial del lenguaje Java que trata las clases internas para obtener más información.


La razón por inner que no se imprime el inner es ( 6.3 ):

El alcance de una declaración de clase local inmediatamente encerrada por un bloque es el resto del bloque de encierro inmediato, incluida su propia declaración de clase.

(Una clase declarada dentro de un método se llama una clase local.)

Entonces, A no puede referirse a la clase local, porque la expresión new A() ocurre antes de su declaración. En otras palabras, las clases locales tienen un alcance similar a las variables locales.

La razón por la que el middle se imprime en lugar de ser outer es que la clase interna A sombrea la clase superior A ( 6.4.1 ):

Una declaración d de un tipo llamado n sombrea las declaraciones de cualquier otro tipo llamado n que estén en el alcance [...] de d .

Esto significa que en cualquier parte del cuerpo de MethodLocalVSInner , el A no calificado debe referirse a la clase interna.

Si está familiarizado con el seguimiento de las variables miembro, por ejemplo:

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

Esencialmente lo mismo está sucediendo con las declaraciones de clase.


Supongo que esperabas que se invocara el método de clase local. Eso no sucedió, porque estás usando un new A() fuera del alcance de la clase local. Por lo tanto, accede al siguiente candidato más cercano en alcance, que sería la clase interna. De JLS §6.3 :

El alcance de una declaración de clase local inmediatamente encerrada por un bloque (§14.2) es el resto del bloque de encierro inmediato, incluida su propia declaración de clase.

Por lo tanto, el new A() en la primera línea del método, no accederá a la clase local que aparece después. Si mueve la declaración de clase antes de eso, obtendrá el resultado esperado.

También vea JLS §14.3 , que contiene un ejemplo similar.


en el método:

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

cuando se inicia la ejecución del método, se ejecutará la primera línea new A().m();

y debido a que la clase interna ya está en el alcance, se creará el objeto para esa clase y se llamará a m method para inner class no para local method class porque todavía no está en el alcance. Es por eso que te estás haciendo middle como resultado.

Pero si cambias tu método como:

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

Su clase de método local ahora estará dentro del alcance y tendrá mayor preferencia, por lo que obtendrá una salida ahora inner .