|
Spec-Zone .ru
спецификации, руководства, описания, API
|
Со следующими проблемами иногда встречаются разработчики, пытаясь вызвать конструкторов через отражение.
ConstructorTrouble пример иллюстрирует то, что происходит, когда код пытается создать новый экземпляр использования class Class.newInstance() и нет никакого доступного конструктора нулевого параметра:
public class ConstructorTrouble {
private ConstructorTrouble(int i) {}
public static void main(String... args){
try {
Class<?> c = Class.forName("ConstructorTrouble");
Object o = c.newInstance(); // InstantiationException
// production code should handle these exceptions more gracefully
} catch (ClassNotFoundException x) {
x.printStackTrace();
} catch (InstantiationException x) {
x.printStackTrace();
} catch (IllegalAccessException x) {
x.printStackTrace();
}
}
}
$ java ConstructorTrouble
java.lang.InstantiationException: ConstructorTrouble
at java.lang.Class.newInstance0(Class.java:340)
at java.lang.Class.newInstance(Class.java:308)
at ConstructorTrouble.main(ConstructorTrouble.java:7)
int параметр препятствует тому, чтобы компилятор генерировал значение по умолчанию (или нулевой параметр) конструктор и в коде нет никакого явного конструктора нулевого параметра. Помните это ведет себя очень как new ключевое слово и перестанет работать всякий раз, когда new перестал бы работать. . А именно, это распространяет любое исключение — проверенный или непроверенный — брошенный конструктором.
import java.lang.reflect.InvocationTargetException;
import static java.lang.System.err;
public class ConstructorTroubleToo {
public ConstructorTroubleToo() {
throw new RuntimeException("exception in constructor");
}
public static void main(String... args) {
try {
Class<?> c = Class.forName("ConstructorTroubleToo");
// Method propagetes any exception thrown by the constructor
// (including checked exceptions).
if (args.length > 0 && args[0].equals("class")) {
Object o = c.newInstance();
} else {
Object o = c.getConstructor().newInstance();
}
// production code should handle these exceptions more gracefully
} catch (ClassNotFoundException x) {
x.printStackTrace();
} catch (InstantiationException x) {
x.printStackTrace();
} catch (IllegalAccessException x) {
x.printStackTrace();
} catch (NoSuchMethodException x) {
x.printStackTrace();
} catch (InvocationTargetException x) {
x.printStackTrace();
err.format("%n%nCaught exception: %s%n", x.getCause());
}
}
}
$ java ConstructorTroubleToo class
Exception in thread "main" java.lang.RuntimeException: exception in constructor
at ConstructorTroubleToo.<init>(ConstructorTroubleToo.java:6)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance
(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance
(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at java.lang.Class.newInstance0(Class.java:355)
at java.lang.Class.newInstance(Class.java:308)
at ConstructorTroubleToo.main(ConstructorTroubleToo.java:15)
Эта ситуация уникальна для отражения. Обычно, невозможно записать код, который игнорирует проверенное исключение, потому что это не скомпилировало бы. Возможно обернуть любое исключение, выданное конструктором при использовании вместо .
$ java ConstructorTroubleToo
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance
(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance
(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at ConstructorTroubleToo.main(ConstructorTroubleToo.java:17)
Caused by: java.lang.RuntimeException: exception in constructor
at ConstructorTroubleToo.<init>(ConstructorTroubleToo.java:6)
... 5 more
Caught exception: java.lang.RuntimeException: exception in constructor
Если бросается, метод был вызван. Диагноз проблемы был бы тем же самым, как будто конструктора вызвали непосредственно и выдал исключение, которое получается . Это исключение не указывает на проблему с отражательным пакетом или его использованием.
import java.lang.reflect.InvocationTargetException;
import static java.lang.System.out;
public class ConstructorTroubleAgain {
public ConstructorTroubleAgain() {}
public ConstructorTroubleAgain(Integer i) {}
public ConstructorTroubleAgain(Object o) {
out.format("Constructor passed Object%n");
}
public ConstructorTroubleAgain(String s) {
out.format("Constructor passed String%n");
}
public static void main(String... args){
String argType = (args.length == 0 ? "" : args[0]);
try {
Class<?> c = Class.forName("ConstructorTroubleAgain");
if ("".equals(argType)) {
// IllegalArgumentException: wrong number of arguments
Object o = c.getConstructor().newInstance("foo");
} else if ("int".equals(argType)) {
// NoSuchMethodException - looking for int, have Integer
Object o = c.getConstructor(int.class);
} else if ("Object".equals(argType)) {
// newInstance() does not perform method resolution
Object o = c.getConstructor(Object.class).newInstance("foo");
} else {
assert false;
}
// production code should handle these exceptions more gracefully
} catch (ClassNotFoundException x) {
x.printStackTrace();
} catch (NoSuchMethodException x) {
x.printStackTrace();
} catch (InvocationTargetException x) {
x.printStackTrace();
} catch (InstantiationException x) {
x.printStackTrace();
} catch (IllegalAccessException x) {
x.printStackTrace();
}
}
}
$ java ConstructorTroubleAgain
Exception in thread "main" java.lang.IllegalArgumentException: wrong number of
arguments
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance
(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance
(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at ConstructorTroubleAgain.main(ConstructorTroubleAgain.java:23)
IllegalArgumentException бросается, потому что конструктора нулевого параметра требовали, и попытка была предпринята, чтобы передать параметр. То же самое исключение было бы выдано, если бы конструктора передали параметр неправильного типа.
$ java ConstructorTroubleAgain int
java.lang.NoSuchMethodException: ConstructorTroubleAgain.<init>(int)
at java.lang.Class.getConstructor0(Class.java:2706)
at java.lang.Class.getConstructor(Class.java:1657)
at ConstructorTroubleAgain.main(ConstructorTroubleAgain.java:26)
Это исключение может произойти, если разработчик по ошибке полагает, что отражение будет автополе или распаковывать типы. Упаковка (преобразование примитива к ссылочному типу) происходит только во время компиляции. Нет никакой возможности в отражении для этой работы, чтобы произойти, таким образом, определенный тип должен использоваться, определяя местоположение конструктора.
$ java ConstructorTroubleAgain Object Constructor passed Object
Здесь, можно было бы ожидать что конструктор, берущий a параметр был бы вызван с тех пор newInstance() был вызван с более определенным String ввести. Однако это слишком поздно! Конструктор, который был найден, уже является конструктором с параметр. newInstance() не предпринимает попытки сделать разрешение метода; это просто работает на существующем объекте конструктора.
new и это new выполняет проверку типа параметра метода, упаковку, и разрешение метода. Ни один из них не происходит в отражении, где явный выбор должен быть сделан. может быть брошен, если попытка предпринимается, чтобы вызвать частное или иначе недоступного конструктора.
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
class Deny {
private Deny() {
System.out.format("Deny constructor%n");
}
}
public class ConstructorTroubleAccess {
public static void main(String... args) {
try {
Constructor c = Deny.class.getDeclaredConstructor();
// c.setAccessible(true); // solution
c.newInstance();
// production code should handle these exceptions more gracefully
} catch (InvocationTargetException x) {
x.printStackTrace();
} catch (NoSuchMethodException x) {
x.printStackTrace();
} catch (InstantiationException x) {
x.printStackTrace();
} catch (IllegalAccessException x) {
x.printStackTrace();
}
}
}
$ java ConstructorTroubleAccess
java.lang.IllegalAccessException: Class ConstructorTroubleAccess can not access
a member of class Deny with modifiers "private"
at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:65)
at java.lang.reflect.Constructor.newInstance(Constructor.java:505)
at ConstructorTroubleAccess.main(ConstructorTroubleAccess.java:15)
Constructor как объявляют, расширяется AccessibleObject который обеспечивает возможность подавить эту проверку через .