Как интерфейсы создают объекты при использовании в анонимных внутренних классах

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

interface A{
   void print();
}

class B{
   public static void main(String args[]){
       A a=new A(){
          void print(){
              System.out.println("Message");
          }
       };
   }
}

Как это A a = new A () возможно, если интерфейс не имеет конструкторов?

Анонимный внутренний класс такой же, как class InternalNameWhoCares implements A.

Phil 07.08.2018 08:22

Ответ в вопросе: это конструктор анонимный внутренний класс, который реализует интерфейс A.

JB Nizet 07.08.2018 08:23
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
2
166
2

Ответы 2

Каждый класс имеет конструктор по умолчанию, который является конструктором без аргументов, если вы не определяете другой конструктор. И анонимный класс, реализующий интерфейс, автоматически сгенерирует его, если вы не определите другой конструктор.

На самом деле это не так. При создании экземпляра анонимного класса вы должны вызвать один из объявленных конструкторов. Не все классы имеют конструкторы по умолчанию.

Logan 07.08.2018 08:31

@Logan Спасибо. Если нет объявленных конструкторов, он будет использовать конструктор по умолчанию, верно?

Jswq 07.08.2018 08:37

Да, это правильно!

Logan 07.08.2018 08:39

Код

interface A {
    void print();
}

class B {
    public static void main(String[] args) {
        A a = new A() {
            public void print() {
                System.out.println("Message");
            }
        };
    }
}

это сокращение для

interface A {
    void print();
}

class B {
    public static void main(String[] args) {
        class B$1 extends java.lang.Object implements A {
            B$1() {
                super();
            }
            public void print() {
                System.out.println("Message");
            }
        }
        A a = new B$1();
    }
}

За одним исключением: если класс B$1 объявлен явно, его можно расширить с помощью class C extends B$1. Однако невозможно расширить анонимный класс B$1 (JLS §8.1.4), даже если он не является final (JLS §8.1.1.2).

То есть анонимные классы по-прежнему остаются классами. Как и все классы (кроме самого java.lang.Object), даже эти классы прямо или косвенно расширяют java.lang.Object. Если анонимный класс указан с использованием интерфейса, он расширяет java.lang.Object и реализует этот интерфейс. Если анонимный класс указан с использованием класса, он расширяет этот класс. Если у конструктора есть аргументы, они передаются в super().

Вы даже можете (хотя это определенно не рекомендуется) вставить A a2 = new B$1(); позже в main(), если хотите. Но на самом деле, не делайте этого, я просто говорю об этом, чтобы показать, что происходит под капотом.

Вы можете наблюдать это сами, поместив исходный код в отдельный каталог, скажем, в AB.java, скомпилировав его, а затем

  • посмотрите на созданные файлы классов.
  • Используйте javap -c B$1, чтобы увидеть, как javac сгенерировал анонимный класс.

Я знаю, что это всего лишь пример, но разве определение вашего класса B$1 не должно выходить за рамки метода main?

Phil 07.08.2018 08:33

@Phil Почему это должно быть вне метода main? В конце концов, это все еще локальный класс, то есть класс, объявленный в методе. Попробуйте добавить метод public void foo() { new B$1(); } - если класс B$1 объявлен вне main(), метод foo() будет компилироваться, если класс B$1 объявлен внутри main(), метод foo() не будет компилироваться.

Christian Hujer 07.08.2018 08:35

Да, вы можете определять классы внутри методов.

Phil 07.08.2018 08:36

Другие вопросы по теме