внутренний класс в интерфейсе - PullRequest
86 голосов
/ 08 марта 2010

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

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

Ответы [ 13 ]

100 голосов
/ 10 декабря 2013

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

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

41 голосов
/ 08 марта 2010

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

40 голосов
/ 07 мая 2012

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

Например:

interface UserChecker {
   Ticket validateUser(Credentials credentials);

   class Credentials {
      // user and password
   }

   class Ticket {
      // some obscure implementation
   }
}

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

30 голосов
/ 16 октября 2014

Цитата из Java 7 spec :

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

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

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

10 голосов
/ 13 февраля 2013

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

7 голосов
/ 08 апреля 2015

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

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);
    ...
}
7 голосов
/ 14 ноября 2014

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

interface MyInterface {

   public static class MyInterfaceException extends Exception {
   }

   void doSomething() throws MyInterfaceException;
}
1 голос
/ 20 октября 2016

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

    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 голос
/ 02 мая 2013

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

0 голосов
/ 14 июня 2017

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

...