Подтвердить что ты не робот

GetDeclaredConstructor на интерфейсе?

В javadoc для Class::getDeclaredConstructor (http://docs.oracle.com/javase/8/docs/api/java/lang/Class.html#getDeclaredConstructor-java.lang.Class...-):

Возвращает объект Constructor, который отражает указанный конструктор класса или интерфейса, представленного этим объектом класса. [акцент мой]

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

Я попробовал его на Runnable.class и получил NoSuchMethodException. Есть ли случай, когда getDeclaredConstructor будет работать на интерфейсе? Или этот язык в javadoc просто ошибка? Или это означает нечто иное, чем то, как я его интерпретирую?

4b9b3361

Ответ 1

Вызов Class.getConstructor приведет к вызову Class.privateGetDeclaredConstructors для извлечения всех объявленных конструкторов. Конструктор соответствия выбирается из этого списка:

private Constructor<T>[] privateGetDeclaredConstructors(boolean publicOnly) {
    ...
    // No cached value available; request value from VM
    if (isInterface()) {
        @SuppressWarnings("unchecked")
        Constructor<T>[] temporaryRes = (Constructor<T>[]) new Constructor<?>[0];
        res = temporaryRes;
    } else {
        res = getDeclaredConstructors0(publicOnly);
    }
    ...
    return res;
}

(я удалил часть кода, которая имеет дело с кэшированными конструкторами).

Итак, для интерфейсов список конструкторов всегда пуст, и всегда будет выбрано NoSuchMethodException.

Ответ 2

Я не считаю это ошибкой в ​​javadoc. Class объект может представлять класс или интерфейс, в этом выражении нет ошибки.

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

Выше я выделил слово конкретный. Например, в аналогичном методе, который возвращает все конструкторы для Class (Class:: getDeclaredConstructors), интерфейсы обрабатываются соответствующим образом:

Возвращает массив объектов Constructor, отражающих все конструкторы, объявленные классом, представленным этим объектом Class. Это общедоступный, защищенный, доступ по умолчанию (пакетный) и частный Конструкторы. Элементы возвращаемого массива не сортируются и не в каком-либо конкретном порядке. Если класс имеет значение по умолчанию конструктор, он включен в возвращенный массив. Этот метод возвращает массив длиной 0, если этот объект Class представляет собой интерфейс, примитивный тип, класс массива или void.

Ответ 3

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

  • Экземпляр класса, вызывающий getClass()
  • Экземпляр интерфейса, вызывающий getClass()
  • Фактический класс ClassX.class
  • Фактический интерфейс Interface.class

    public class Testctor {
    
        public static void main(String[] args) {
            new Testctor().testGetDeclCtors();
        }
    
        public void testGetDeclCtors() {
            Class1 c1 = new Class1(4);
            printClassInfo(c1.getClass());
    
            I2 i2 = c1;
            printClassInfo(i2.getClass());
    
            printClassInfo(Class1.class);
    
            printClassInfo(I2.class);
        }
    
        private void printClassInfo(Class<?> claz) {
            Constructor<?> ctor = null;
            try {
                ctor = claz.getDeclaredConstructor();
            } catch (NoSuchMethodException | SecurityException e) {
            }
            System.out.println(claz+": "+ctor);
        }
    }
    
    interface I2 {
    }
    
    class Class1 implements I2 {
        public Class1() {
        }
    
        public Class1(int x) {
        }
    }
    

Это выводит эти результаты:

class test.Class1: public test.Class1()
class test.Class1: public test.Class1()
class test.Class1: public test.Class1()
interface test.I2: null