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


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

Они помогают в любом процессе развития?

13 78

13 ответов:

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

в любом случае, следующие компилирует штрафа:

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 кодовая база здесь, где это происходит точно нулевое время (но тогда у нас есть много других вещей, которые мы считаем плохими практиками, которые происходят точно нулевое время тоже, что другие люди найдут совершенно нормальным так...).

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

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(). Наличие их внутри входного интерфейса улучшает когезию.

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

пример:

interface UserChecker {
   Ticket validateUser(Credentials credentials);

   class Credentials {
      // user and password
   }

   class Ticket {
      // some obscure implementation
   }
}

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

цитата Java 7 spec:

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

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

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

интересным вариантом использования является предоставление своего рода реализации по умолчанию для интерфейсных методов через внутренний класс, как описано здесь:https://stackoverflow.com/a/3442218/454667 (чтобы преодолеть проблему наследования одного класса).

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

interface MyInterface {

   public static class MyInterfaceException extends Exception {
   }

   void doSomething() throws MyInterfaceException;
}

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

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);
    ...
}

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

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

    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();
    }
}

может обеспечить некоторые статические реализации, но не будет ли это запутанным, я не знаю.

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

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

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

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

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

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

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

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