Pergunta

O código no final produz um erro de compilação:

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

A questão é por quê? Por que javac acha que eu estou chamando run (), e não encontra run (int bar)? -Lo corretamente chamado foo (int bar). Por que eu tenho que usar NotApplicable.this.run (42) ;? É um bug?

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) {
    }
}
Foi útil?

Solução

A explicação para o comportamento do seu exemplo de código é que this é definido como sendo a classe que você está atualmente dentro "a maioria" de. Neste caso, você é "mais" dentro da classe interna anônima que subclasses executável e não existe um método que combina run(int). Para alargar a sua pesquisa que você especificar quais this que deseja utilizar, afirmando NotApplicable.this.run(42).

A JVM irá avaliar o seguinte:

this -> atualmente em execução instância de Runnable com run() método

NotApplicable.this -> atualmente em execução instância de NotApplicable com run(int) método

O compilador irá procurar a árvore de nidificação para o primeiro método que corresponda ao nome do método. -Obrigado para DJClayworth para este esclarecimento

A classe interna anônima não é uma subclasse da classe externa. Devido a esta relação, tanto a classe interna e da classe externa deve ser capaz de ter um método com exatamente a mesma assinatura e o bloco de código mais interna deve ser capaz de identificar qual o método que pretende executar.

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" );
    }
}

Outras dicas

Tanto quanto eu recordar as regras para a seleção de um método para executar entre classes aninhadas são aproximadamente o mesmo que as regras para a seleção de um método em uma árvore de herança. Isso significa que o que estamos recebendo aqui não é sobrecarga, ele está escondendo. A diferença entre estes é crucial para métodos de compreensão em herança.

Se o seu Runnable foi declarada como uma subclasse, então o método run () iria esconder o (int) método no pai prazo. Qualquer chamada para execução (...) iria tentar executar a um em Runnable, mas seria um fracasso se não poderia coincidir com assinaturas. Desde foo não é declarado na criança, em seguida, a da mãe é chamado.

O mesmo princípio está acontecendo aqui. Olhe-se referências a "esconder método" e deve ficar claro.

Isto porque run está sendo re-declarada quando você entra no âmbito new Runnable() {}. Todas as ligações anteriores para executar tornam-se inacessíveis. É como se você estivesse fazendo isso:

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();
  }
}

O compilador não vai olhar para algo que corresponde ao tipo de x todo o caminho até a pilha de escopo, ele só vai parar quando encontrar as primeiras referências e vê que os tipos são incompatíveis.

NOTA: Não é como se não fazer isso ... é só que, para preservar a sua própria sanidade, ele foi decidido que não deveria .

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top