2010-03-08 3 views
70

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

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

ответ

33

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

+0

Можете добавить несколько примеров использования? Я уже некоторое время тестировал что-то подобное и не понял, что могу получить от использования этой конструкции. – Roman

+0

@ Roman: Я помню, что я столкнулся с этим в каком-то проекте (относительно чистый проект я бы добавил, но они не были моими), но я не знаю, действительно ли это чисто или нет. Я добавил крошечный пример, который выглядит так, как я видел, но еще раз: это был не мой код, и я не использую эту конструкцию, поэтому я не самый квалифицированный, чтобы придумать правильные примеры :) IIRC внутренний класс всегда назывался, например * StateChecker *, и вызовы всегда выглядели бы так: * A.StateChecker.check (a) * или что-то в этом роде. – SyntaxT3rr0r

+4

Если вы скажете, что «нет такой вещи, как« статический внутренний класс »*, ваш ответ, что« вы * можете * создать как вложенный класс, так и внутренний класс внутри интерфейса Java »в корне неверен. Используя суженное определение, '' '' '' '' '' '' '' '' '' имеют внутренние классы. Вы можете опустить модификатор 'static' вложенного класса' interface', но все же это вложенный класс, а не внутренний класс. – Holger

37

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

К примеру:

interface UserChecker { 
    Ticket validateUser(Credentials credentials); 

    class Credentials { 
     // user and password 
    } 

    class Ticket { 
     // some obscure implementation 
    } 
} 

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

8

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

1

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

79

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

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

+8

Действительно хороший пример, это должно иметь больше upvotes! – Levit

+2

@ Levit Просто интересно, как будет выглядеть реализованный класс? – overexchange

+0

Хотелось бы увидеть реализацию в действии для вышеуказанного использования. Спасибо. –

19

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

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

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

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

+0

Спасибо. Это, наверное, самый краткий ответ. – Joseph

7

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

interface MyInterface { 

    public static class MyInterfaceException extends Exception { 
    } 

    void doSomething() throws MyInterfaceException; 
} 
6

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

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

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

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

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

0

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

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

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

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

Это ваш интерфейс, и это будет implementee:

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

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

0

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

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

0

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

Смежные вопросы