Pregunta

El código al final produce un error de compilación:

NotApplicable.java:7: run() in  cannot be applied to (int)
                run(42);
                ^
1 error

La pregunta es ¿por qué? ¿Por qué javac piensa que estoy llamando a run () y no encuentra run (int bar)? Se llama correctamente foo (int bar). ¿Por qué tengo que usar NotApplicable.this.run (42) ;? ¿Es un error?

public class NotApplicable {

    public NotApplicable() {
        new Runnable() {
            public void run() {
                foo(42);
                run(42);
                // uncomment below to fix
                //NotApplicable.this.run(42);
            }
        };
    }

    private void run(int bar) {
    }

    public void foo(int bar) {
    }
}
¿Fue útil?

Solución

La explicación del comportamiento de su ejemplo de código es que this se define como la clase en la que actualmente se encuentra " most " dentro de. En este caso, eres " más " dentro de la clase interna anónima, las subclases son ejecutables y no hay ningún método que coincida con run (int) . Para ampliar su búsqueda, especifique qué esto desea utilizar indicando NotApplicable.this.run (42) .

El jvm evaluará lo siguiente:

esto - > actualmente se ejecuta la instancia de Runnable con el método run()

NotApplicable.this - > actualmente ejecutando la instancia de NotApplicable con el método run(int)

El compilador buscará el árbol de anidamiento para el primer método que coincida con el NOMBRE del método. –Gracias a DJClayworth por esta aclaración

La clase interna anónima no es una subclase de la clase externa. Debido a esta relación, tanto la clase interna como la clase externa deberían poder tener un método con exactamente la misma firma y el bloque de código más interno debería poder identificar qué método desea ejecutar.

public class Outer{

    public Outer() {
        new Runnable() {
            public void printit() {
                System.out.println( "Anonymous Inner" );
            }
            public void run() {
                printit(); // prints "Anonymous Inner"
                this.printit(); //prints "Anonymous Inner"

                // would not be possible to execute next line without this behavior
                Outer.this.printit(); //prints "Outer" 
            }
        };
    }

    public void printit() {
        System.out.println( "Outer" );
    }
}

Otros consejos

Por lo que recuerdo, las reglas para seleccionar un método para ejecutarse entre clases anidadas son aproximadamente las mismas reglas para seleccionar un método en un árbol de herencia. Eso significa que lo que estamos obteniendo aquí no es sobrecargar, se está escondiendo. La diferencia entre estos es crucial para comprender los métodos de herencia.

Si su Runnable fue declarado como una subclase, entonces el método run () ocultaría el método run (int) en el padre. Cualquier llamada a ejecutar (...) intentaría ejecutar la de Runnable, pero fallaría si no pudiera coincidir con las firmas. Como foo no está declarado en el hijo, se llama al del padre.

El mismo principio está sucediendo aquí. Busque referencias al " método que oculta " y debería estar claro.

Esto se debe a que run se vuelve a declarar cuando se ingresa en el new Runnable () {} . Todos los enlaces anteriores para ejecutar se vuelven inaccesibles. Es como si estuvieras haciendo esto:

import java.util.*;

public class tmp
{
  private int x = 20;
  public static class Inner
  {
      private List x = new ArrayList();
      public void func()
      {
          System.out.println(x + 10);
      }
  }

  public static void main(String[] args)
  {
    (new Inner()).func();
  }
}

El compilador no buscará algo que coincida con el tipo de x hasta el final de la pila de alcance, solo se detendrá cuando encuentre las primeras referencias y verá que los tipos son incompatibles .

NOTA: No es como si no pudiera hacer esto ... es solo eso, para preservar tu propia cordura, se ha decidido que no debería .

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top