Анонимный внутренний класс, объявленный в интерфейсе: что такое внешний класс?

Рассмотрим следующее:

public class OuterClass {

    private String attribute = "outer";

    class InnerClass {
        private String attribute = "inner";
        public doSomething() {
            System.out.println(this.attribute);
            System.out.println(OuterClass.this.attribute);

        }
    }

}

InnerClass не является статическим и должен быть создан для экземпляра его внешнего класса.

new OuterClass().new InnerClass()

Обычный внутренний класс содержит ссылку на внешний класс, в котором он был создан, доступ к которому осуществляется с помощью Outer.this.myAttribute (особенно полезно в этом случае, когда существует "конфликт имен"


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

public class OuterClass {

  // Do not need to be final because the innerclass keeps a reference to the outerclass
  // even if it's an anonymous innerclass, it's still an innerclass
  private String classAttribute = "classAttribute";

  public Runnable doSomething() {

    // Should be final because the variable lives on the stack and the reference to this object
    // must be copied so that the String object is still accessible when the stack frame is destroyed
    final String localVar = "localVar";

    return new Runnable() {
      @Override
      public void run() {
        System.out.println(classAttribute);
        System.out.println(localVar);
      }
    };
  }

}

И, наконец, мы можем объявить константы в интерфейсе, которые неявно помечены как public static final. Объект может быть константой. Таким образом, объект, созданный как анонимный внутренний класс, является допустимой константой для интерфейса.

Например, при использовании Guava я обычно объявляю в своем интерфейсе функции и предикаты, что позволяет мне использовать полезные функции Guava, такие как Maps.uniqueIndex(...).

public interface AlternativeNameable {

  String getAlternativeName();

  Function<AlternativeNameable,String> GET_ALTERNATIVE_NAME = new Function<AlternativeNameable,String>() {
    @Override
    public String apply(AlternativeNameable input) {
      return input.getAlternativeName();
    }
  };

}

Итак, вы можете спросить себя, в чем мой вопрос? Вот:

При объявлении анонимного класса в качестве константы интерфейса (см. мой последний пример кода), на какой внешний класс ссылается анонимный внутренний класс?


person Sebastien Lorber    schedule 09.11.2012    source источник
comment
Только что попробовал, и в экземпляре функции вообще нет атрибута   -  person Sebastien Lorber    schedule 09.11.2012


Ответы (2)


Внутренние классы интерфейсов неявно статичны и поэтому не требуют ссылки на внешний класс.

person Alexei Kaigorodov    schedule 09.11.2012
comment
То есть вы имеете в виду, что анонимный внутренний класс в этом особом случае действует как анонимный статический внутренний класс? Я понимаю концепцию, но есть ли у вас ссылка, которая объясняет это? - person Sebastien Lorber; 09.11.2012
comment
@SebastienLorber docs.oracle.com/ javase/specs/jls/se7/html/jls-9.html#jls-9.5 - person Sean Patrick Floyd; 09.11.2012

Поля, определенные в интерфейсах , всегда неявно имеют модификаторы public static final. Это константа, и поэтому у нее нет связанного внешнего класса.

Кроме того, типы-члены интерфейсов неявно являются общедоступными и статическими, что верно и для анонимных классов.

person Sean Patrick Floyd    schedule 09.11.2012
comment
Итак, подразумеваемый static является ключом здесь? - person John Dvorak; 09.11.2012
comment
Это и подразумеваемый static самого интерфейса. Интерфейсы, перечисления и аннотации всегда static. - person Sean Patrick Floyd; 09.11.2012
comment
Это я объясняю. Но тот факт, что ссылка на эту функцию является статической, не объясняет, почему она не ведет себя как другой анонимный внутренний класс. Действительно возможно хранить статическую ссылку на произвольно объявленный класс, который ссылается на внешний класс. - person Sebastien Lorber; 09.11.2012
comment
@SebastienLorber см. ответ Алексея - person Sean Patrick Floyd; 09.11.2012