it-roy-ru.com

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

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

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

79
gmhk

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

37
SyntaxT3rr0r

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

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

92
zafar142003

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

К примеру:

interface UserChecker {
   Ticket validateUser(Credentials credentials);

   class Credentials {
      // user and password
   }

   class Ticket {
      // some obscure implementation
   }
}

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

40
helios

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

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

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

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

28
Nad Nik

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

10
Bachi

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

interface MyInterface {

   public static class MyInterfaceException extends Exception {
   }

   void doSomething() throws MyInterfaceException;
}
7
Michael Anderson

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

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

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

1
Henno Vermeulen

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

    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
Ilian Zapryanov

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

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

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

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

0
user214420

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

0
dehasi

Я нашел применение для этого типа конструкции.

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

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

0
Venkat K