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

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

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

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

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

Ответ 1

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

Нет, это все еще внутренний класс, который указывает имя файла (IIRC it 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
     }
  }
}

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

Ответ 2

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

* вид

Ответ 3

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

Ответ 4

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