Почему я не могу вызвать метод вне анонимного класса с тем же именем

StackOverflow https://stackoverflow.com/questions/252267

Вопрос

Код в конце выдает ошибку компиляции:

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

Вопрос в том, почему? Почему javac считает, что я вызываю run (), и не находит run (int bar)? Это правильно называется foo (int bar). Почему я должен использовать NotApplicable.this.run (42) ;? Это ошибка?

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) {
    }
}
Это было полезно?

Решение

Объяснение поведения вашего примера кода состоит в том, что this определено как класс, который вы в настоящее время " наиболее " Внутри. В этом случае вы «самый» внутри анонимного внутреннего класса, который подклассы являются работоспособными, и нет метода, который соответствует run (int) . Чтобы расширить поиск, укажите, какой этот вы хотите использовать, указав NotApplicable.this.run (42) .

jvm будет оцениваться следующим образом:

this - > в настоящее время выполняется экземпляр Runnable с методом run ()

NotApplicable.this - > в настоящий момент выполняется экземпляр NotApplicable с методом run (int)

Компилятор ищет дерево вложенности для первого метода, который соответствует ИМЯ метода. & # 8211; Спасибо DJClayworth за это разъяснение

Анонимный внутренний класс не является подклассом внешнего класса. Из-за этой взаимосвязи и внутренний класс, и внешний класс должны иметь метод с точно такой же сигнатурой, а самый внутренний блок кода должен иметь возможность определить, какой метод он хочет запустить.

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

Другие советы

Насколько я помню, правила выбора метода для запуска между вложенными классами примерно такие же, как правила выбора метода в дереве наследования. Это означает, что то, что мы получаем, не перегружено, оно скрыто. Разница между ними имеет решающее значение для понимания методов наследования.

Если ваш Runnable был объявлен как подкласс, то метод run () скрыл бы метод run (int) в родительском объекте. Любой вызов run (...) попытался бы выполнить вызов в Runnable, но потерпел бы неудачу, если он не мог соответствовать сигнатурам. Поскольку foo не объявлен в потомке, то вызывается тот, что у родителя.

Тот же принцип происходит здесь. Посмотрите ссылки на "метод сокрытия" и это должно быть понятно.

Это потому, что run повторно объявляется при входе в область действия new Runnable () {} . Все предыдущие привязки к запуску становятся недоступными. Это как если бы вы делали это:

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

Компилятор не будет искать то, что соответствует типу x , до конца стека областей, он просто остановится, когда найдет первые ссылки и обнаружит, что типы несовместимы .

ПРИМЕЧАНИЕ. Дело не в том, что не может сделать это ... просто для сохранения собственного здравого смысла было решено, что не следует .

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top