Почему статический вложенный интерфейс будет использоваться в Java? - PullRequest
230 голосов
/ 16 сентября 2008

Я только что нашел статический вложенный интерфейс в нашей базе кода.

class Foo {
    public static interface Bar {
        /* snip */
    }
    /* snip */
}

Я никогда не видел этого раньше. Оригинальный разработчик недоступен. Поэтому я должен спросить ТАК:

Какова семантика статического интерфейса? Что изменится, если я уберу static? Зачем кому-то это делать?

Ответы [ 11 ]

290 голосов
/ 16 сентября 2008

Ключевое слово static в приведенном выше примере является избыточным (вложенный интерфейс автоматически становится «статическим») и может быть удалено без влияния на семантику; Я бы порекомендовал его убрать. То же самое касается «public» в интерфейсных методах и «public final» в интерфейсных полях - модификаторы являются избыточными и просто добавляют беспорядок в исходный код.

В любом случае, разработчик просто объявляет интерфейс с именем Foo.Bar. Дальнейшая связь с классом включения отсутствует, за исключением того, что код, который не может получить доступ к Foo, также не сможет получить доступ к Foo.Bar. (Из исходного кода - байт-код или отражение могут получить доступ к Foo.Bar, даже если Foo является частным для пакета!)

Это приемлемый стиль для создания вложенного интерфейса таким образом, если вы ожидаете, что он будет использоваться только из внешнего класса, чтобы вы не создавали новое имя верхнего уровня. Например:

public class Foo {
    public interface Bar {
        void callback();
    }
    public static void registerCallback(Bar bar) {...}
}
// ...elsewhere...
Foo.registerCallback(new Foo.Bar() {
    public void callback() {...}
});
71 голосов
/ 16 октября 2008

На вопрос дан ответ, но одна из веских причин использовать вложенный интерфейс - если его функция напрямую связана с классом, в котором он находится. Хороший пример этого - Listener. Если у вас есть класс Foo и вы хотите, чтобы другие классы могли прослушивать события в нем, вы можете объявить интерфейс с именем FooListener, что нормально, но, вероятно, было бы более понятно объявить вложенный интерфейс пусть эти другие классы реализуют Foo.Listener (вложенный класс Foo.Event неплох с этим).

13 голосов
/ 17 сентября 2008

Интерфейсы-члены неявно статичны. Модификатор static в вашем примере может быть удален без изменения семантики кода. См. Также Спецификацию языка Java 8.5.1. Декларации типов статических элементов

9 голосов
/ 16 сентября 2008

Внутренний интерфейс должен быть статическим для доступа. Интерфейс связан не с экземплярами класса, а с самим классом, поэтому к нему можно получить доступ с помощью Foo.Bar, например:

public class Baz implements Foo.Bar {
   ...
}

В большинстве случаев это не отличается от статического внутреннего класса.

6 голосов
/ 16 января 2013

Ответ Джесси близок, но я думаю, что есть лучший код, чтобы продемонстрировать, почему внутренний интерфейс может быть полезен. Посмотрите на код ниже, прежде чем читать дальше. Можете ли вы найти, почему внутренний интерфейс полезен? Ответ заключается в том, что класс DoSomethingAlready можно создать с помощью любого класса, который реализует A и C; не только конкретный класс зоопарка. Конечно, это может быть достигнуто, даже если AC не является внутренним, но представьте, что объединяете более длинные имена (не только A и C) и делаете это для других комбинаций (скажем, A и B, C и B и т. Д.), И вы легко Посмотрите, как все выходит из-под контроля. Не говоря уже о том, что люди, просматривающие ваше дерево исходников, будут перегружены интерфейсами, которые имеют смысл только в одном классе. Итак, подведем итог, внутренний интерфейс позволяет создавать пользовательские типы и улучшает их инкапсуляцию .

class ConcreteA implements A {
 :
}

class ConcreteB implements B {
 :
}

class ConcreteC implements C {
 :
}

class Zoo implements A, C {
 :
}

class DoSomethingAlready {
  interface AC extends A, C { }

  private final AC ac;

  DoSomethingAlready(AC ac) {
    this.ac = ac;
  }
}
3 голосов
/ 16 сентября 2008

Чтобы ответить на ваш вопрос очень прямо, посмотрите на Map.Entry.

Map.Entry

также это может быть полезно

Статическая вложенная запись в блоге Inerfaces

0 голосов
/ 12 августа 2015

В 1998 году Филипп Вадлер предложил различие между статическими интерфейсами и нестатическими интерфейсами.

Насколько я вижу, единственная разница в создании Нестатический интерфейс является то, что теперь он может включать в себя нестатический внутренний классы; поэтому изменение не сделает недействительным любую существующую Java программы.

Например, он предложил решение проблемы с выражением , которая представляет собой несоответствие между выражением «сколько может выразить ваш язык», с одной стороны, и выражением как «терминами, которые вы пытаетесь представлять на своем языке "с другой стороны.

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

// This code does NOT compile
class LangF<This extends LangF<This>> {
    interface Visitor<R> {
        public R forNum(int n);
    }

    interface Exp {
        // since Exp is non-static, it can refer to the type bound to This
        public <R> R visit(This.Visitor<R> v);
    }
}

Его предложение никогда не делалось в Java 1.5.0. Следовательно, все остальные ответы верны: нет разницы между статическими и нестатическими вложенными интерфейсами.

0 голосов
/ 14 мая 2015

Если вы замените класс Foo на интерфейс Foo, ключевое слово public в приведенном выше примере также будет избыточным, поскольку

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

0 голосов
/ 16 сентября 2008

В Java статический интерфейс / класс позволяет использовать интерфейс / класс как класс верхнего уровня, то есть он может быть объявлен другими классами. Итак, вы можете сделать:

class Bob
{
  void FuncA ()
  {
    Foo.Bar foobar;
  }
}

Без статики вышеприведенное не скомпилируется. Преимущество этого в том, что вам не нужен новый исходный файл только для объявления интерфейса. Он также визуально связывает интерфейс Bar с классом Foo, поскольку вы должны написать Foo.Bar, и подразумевает, что класс Foo что-то делает с экземплярами Foo.Bar.

Описание типов классов в Java .

0 голосов
/ 16 сентября 2008

Статический означает, что любая часть класса пакета (проекта) может получить к нему доступ без использования указателя. Это может быть полезно или мешать в зависимости от ситуации.

Прекрасным примером использования "статических" методов является класс Math. Все методы в математике являются статическими. Это означает, что вам не нужно выходить из своего пути, создавать новый экземпляр, объявлять переменные и сохранять их в еще большем количестве переменных, вы можете просто ввести свои данные и получить результат.

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

Статические методы хороши для одноразовых возвратов и быстрых вычислений или легко получаемых данных.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...