Можно ли создать внутренний класс в интерфейсе?
Если это возможно, зачем нам создавать такой внутренний класс, если мы не собираемся создавать какие-либо объекты интерфейса?
Помогают ли эти внутренние классы в любом процессе разработки?
Ответы:
Да, вы можете создать как вложенный класс, так и внутренний класс внутри интерфейса 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 здесь, где это происходит точно в нулевое время (но тогда у нас есть много других вещей, которые мы считаем плохими практиками, которые тоже происходят точно в нулевое время, что другие люди сочли бы совершенно нормальным, так что ...).
interface
s не может иметь внутренних классов. Вы можете опустить static
модификатор interface
вложенного класса, но все же это вложенный класс, а не внутренний класс.
B
класс будет статическим вложенным классом, а не внутренним классом; Особый подход к интерфейсам. Я не смог найти упоминания об этом в Интернете, за исключением самой спецификации: «Класс-член интерфейса неявно статичен, поэтому никогда не считается внутренним классом». docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.1.3
Да, у нас могут быть классы внутри интерфейсов. Одним из примеров использования может быть
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, - это определение объектов, которые принимаются или возвращаются включающими методами интерфейса. Обычно структуры хранения данных. Таким образом, если объект используется только для этого интерфейса, у вас все будет более связным.
По примеру:
interface UserChecker {
Ticket validateUser(Credentials credentials);
class Credentials {
// user and password
}
class Ticket {
// some obscure implementation
}
}
Но все равно ... это дело вкуса.
Цитата из спецификации Java 7 :
Интерфейсы могут содержать объявления типов членов (§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 или шаблон миксинов?
Может быть, если вам нужны более сложные конструкции, такие как различные варианты поведения, подумайте:
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();
}
}
Могут предоставить некоторые статические реализации, но разве это не сбивает с толку, я не знаю.
Я нашел применение этому типу конструкции.
У вас есть доступ ко всем сгруппированным константам; имя класса в этом случае действует как пространство имен.
Мне он нужен прямо сейчас. У меня есть интерфейс, в котором было бы удобно возвращать уникальный класс из нескольких его методов. Этот класс имеет смысл только как контейнер для ответов от методов этого интерфейса.
Следовательно, было бы удобно иметь статическое определение вложенного класса, которое связано только с этим интерфейсом, поскольку этот интерфейс должен быть единственным местом, где когда-либо создается этот класс контейнера результатов.