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:
- bloquear
- método
- clase
- 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 llamadon
sombrea las declaraciones de cualquier otro tipo llamadon
que estén en el alcance [...] ded
.
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
.