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 просто ошибка? Или это означает нечто иное, чем то, как я его интерпретирую?
Ответы
Ответ 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