Внутренний класс внутри интерфейса

Можно ли создать внутренний класс в интерфейсе? Если это возможно, почему мы хотим создать такой внутренний класс, так как мы не собираемся создавать какие-либо объекты интерфейса?

Помогают ли эти внутренние классы в любом процессе разработки?

Ответ 1

Да, вы можете создать как вложенный класс, так и внутренний класс внутри интерфейса Java (обратите внимание, что вопреки распространенному мнению нет такой вещи, как "статический внутренний класс": это просто не имеет смысла, нет ничего "внутреннего", и нет класса "outter", когда вложенный класс статичен, поэтому он не может быть "статическим внутренним" ).

В любом случае, компилируются следующие компиляции:

public interface A {
    class B {
    }
}

Я видел, как он использовал какой-то "контролер транзакций" непосредственно в определении интерфейса (ну, в классе, вложенном в интерфейс, который может иметь статические методы, в противоположность самому интерфейсу, который не может). Если я правильно помню, выглядите так.

public interface A {
    static class B {
        public static boolean verifyState( A a ) {
            return (true if object implementing class A looks to be in a valid state)
        }
    }
}

Обратите внимание, что я не комментирую полезность такой вещи, я просто отвечаю на ваш вопрос: это можно сделать, и это одно из видов использования, которое я видел из этого.

Теперь я не буду комментировать полезность такой конструкции, и я видел: я ее видел, но это не очень общая конструкция.

200KLOC codebase здесь, где это происходит ровно нулевое время (но тогда у нас есть много других вещей, которые мы считаем плохими практиками, которые происходят ровно нулевое время, так что другие люди будут находить совершенно нормальные так...).

Ответ 2

Да, мы можем иметь классы внутри интерфейсов. Одним из примеров использования может быть

public interface Input
{
    public static class KeyEvent {
         public static final int KEY_DOWN = 0;
         public static final int KEY_UP = 1;
         public int type;
         public int keyCode;
         public char keyChar;
    }
    public static class TouchEvent {
         public static final int TOUCH_DOWN = 0;
         public static final int TOUCH_UP = 1;
         public static final int TOUCH_DRAGGED = 2;
         public int type;
         public int x, y;
         public int pointer;
    }
    public boolean isKeyPressed(int keyCode);
    public boolean isTouchDown(int pointer);
    public int getTouchX(int pointer);
    public int getTouchY(int pointer);
    public float getAccelX();
    public float getAccelY();
    public float getAccelZ();
    public List<KeyEvent> getKeyEvents();
    public List<TouchEvent> getTouchEvents();
}

Здесь код имеет два вложенных класса, которые предназначены для инкапсуляции информации о объектах событий, которые позже используются в определениях методов, таких как getKeyEvents(). Наличие их внутри интерфейса ввода улучшает сцепление.

Ответ 3

Действительное использование, IMHO, определяет объекты, которые получены или возвращены приложенными методами интерфейса. Типично структуры хранения данных. Таким образом, если объект используется только для этого интерфейса, у вас есть вещи более сплоченно.

Пример:

interface UserChecker {
   Ticket validateUser(Credentials credentials);

   class Credentials {
      // user and password
   }

   class Ticket {
      // some obscure implementation
   }
}

Но во всяком случае... это только вопрос вкуса.

Ответ 4

Цитата из спецификации Java 7:

Интерфейсы могут содержать объявления типа члена (§8.5).

Объявление типа элемента в интерфейсе является неявным статичным и общедоступным. Разрешено избыточно указывать один или оба этих модификатора.

Невозможно объявить нестатические классы внутри интерфейса Java, что имеет смысл для меня.

Ответ 5

Интересным вариантом использования является предоставление по умолчанию реализации методов интерфейса через внутренний класс, как описано здесь: fooobar.com/questions/83483/... (для преодоления проблемы одиночного -класс-наследование).

Ответ 6

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

interface MyInterface {

   public static class MyInterfaceException extends Exception {
   }

   void doSomething() throws MyInterfaceException;
}

Ответ 7

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

public interface User {
    public enum Role {
        ADMIN("administrator"),
        EDITOR("editor"),
        VANILLA("regular user");

        private String description;

        private Role(String description) {
            this.description = description;
        }

        public String getDescription() {
            return description;
        }
    }

    public String getName();
    public void setName(String name);
    public Role getRole();
    public void setRole(Role role);
    ...
}

Ответ 8

То, что @Bachi упоминает, похоже на черты в Scala и фактически реализовано с использованием вложенного класса внутри интерфейса. Это можно моделировать на Java. См. Также java черты или шаблон mixins?

Ответ 9

Может быть, когда вам нужны более сложные конструкции, такие как различные варианты реализации, подумайте:

public interface A {
    public void foo();

    public static class B implements A {
        @Override
        public void foo() {
            System.out.println("B foo");
        }
    }
}

Это ваш интерфейс и его реализация:

public class C implements A {
    @Override
    public void foo() {
        A.B b = new A.B();
        b.foo(); 
    }

    public static void main(String[] strings) {
        C c = new C();
        c.foo();
    }
}

Может предоставить несколько статических реализаций, но разве это не смущает, я не знаю.

Ответ 10

Я нашел использование этого типа конструкции.

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

У вас есть доступ ко всем константам, сгруппированным; в этом случае имя класса действует как пространство имен.

Ответ 11

Вы также можете создавать статические классы "Помощник" для общей функциональности для объектов, реализующих этот интерфейс:

public interface A {
    static class Helper {
        public static void commonlyUsedMethod( A a ) {
           ...
        }
    }
}

Ответ 12

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

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

Ответ 13

Например traits (smth-подобный интерфейс с реализованными методами) в Groovy. Они скомпилированы для интерфейса, который содержит внутренний класс, где реализованы все методы.