Почему интерфейс может быть объявлен только в классе верхнего уровня? - PullRequest
10 голосов
/ 23 августа 2011

Хорошо, я знаю, что это правило:

Согласно JLS: 8.1.3. Внутренние классы и вложенные экземпляры, внутренние классы могут не объявлять статические инициализаторы или интерфейсы-члены.Внутренние классы могут не объявлять статические члены, если они не являются постоянными полями времени компиляции.

Согласно 8.5.2 Декларации типов статических членов, «Интерфейсы-члены всегда неявно статичны. Это разрешено, но не требуется для объявленияинтерфейса члена для явного перечисления статического модификатора ".Они всегда на высшем уровне, а не внутри.

Мне просто интересно, почему.Что может произойти, если нам разрешено объявлять интерфейс внутри внутреннего класса?Не станет ли внутренний класс классом верхнего уровня, если я помещу его в другой файл класса?

Ответы [ 4 ]

7 голосов
/ 23 августа 2011

Не станет ли внутренний класс классом верхнего уровня, если я помещу его в другой файл класса?

Нет, это все еще внутренний класс, который указывает имя файла (IIRC этоOuterClass$InnerClass.class).

Внутренние классы имеют доступ к атрибутам внешнего класса, т.е. они зависят от экземпляра своего внешнего класса.С интерфейсами вы не могли этого сделать.Представьте себе совершенно не связанный класс, который должен быть создан экземпляром соответствующего внешнего класса.Как бы это сделать, если внешний класс не знает, кто реализует этот интерфейс?

Что вы можете сделать, это объявить статические интерфейсы в вашем внешнем классе, таким образом, просто используя внешний в качестве пространства имен:

public class OuterClass {
  public static interface InnerInterface { //protected and private would be fine too, depending on what makes sense
  }
}

Редактировать: на самом деле, я неправильно понял вопрос, и поскольку интерфейсы в любом случае являются статическими, вот обновленный фрагмент кода:

 public class OuterClass {
  public static InnerClass { //static inner class making OuterClass just be a namespace
     public interface InnerInnerInterface { //protected and private would be fine too, depending on what makes sense
     }
  }
}

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

4 голосов
/ 23 августа 2011

Думайте об этом с точки зрения статического и нестатического контекста. Класс «верхнего уровня» устанавливает статический контекст, поскольку к нему можно получить доступ без какого-либо включающего экземпляра. То есть Вы можете получить доступ к классам верхнего уровня из основного метода. То же относится и к любым статическим членам класса верхнего уровня. Внутренний класс, однако, не существует в * и не устанавливает никакого статического контекста. Поэтому он не может иметь никаких статических членов, и к нему можно получить доступ только через экземпляр содержащего его класса, например, конструкторы и другие члены экземпляра. Из основного метода вы не сможете сказать Outer.Inner.SOME_FIELD, потому что члены внутреннего класса имеют значение только по отношению к содержащему классу.

* сорт

2 голосов
/ 23 августа 2011

По определению класс верхнего уровня и его внутренний класс (классы) тесно связаны.Интерфейсы являются средством уменьшения сцепления.

1 голос
/ 23 августа 2011

Предполагается, что внутренние классы являются деталями реализации класса верхнего уровня и поэтому должны быть невидимы для клиента. Любая функциональность, к которой вы хотите получить доступ из внутреннего класса, должна выполняться через класс верхнего уровня, потому что, с концептуальной точки зрения, эта функциональность должна быть видимой только как функциональность класса верхнего уровня, чтобы разработчик класса мог поменяться или иным образом радикально изменить внутренние классы, не нарушая сборки клиентов.

...