|
Spec-Zone .ru
спецификации, руководства, описания, API
|
Этот раздел содержит примеры трудных разработчиков, мог бы встретиться при использовании отражения, чтобы определить местоположение, вызвать, или получить информацию о методах.
пример иллюстрирует то, что происходит, когда стирание типа не учитывается кодом, который ищет определенный метод в class.MethodTrouble
import java.lang.reflect.Method;
public class MethodTrouble<T> {
public void lookup(T t) {}
public void find(Integer i) {}
public static void main(String... args) {
try {
String mName = args[0];
Class cArg = Class.forName(args[1]);
Class<?> c = (new MethodTrouble<Integer>()).getClass();
Method m = c.getMethod(mName, cArg);
System.out.format("Found:%n %s%n", m.toGenericString());
// production code should handle these exceptions more gracefully
} catch (NoSuchMethodException x) {
x.printStackTrace();
} catch (ClassNotFoundException x) {
x.printStackTrace();
}
}
}
$ java MethodTrouble lookup java.lang.Integer
java.lang.NoSuchMethodException: MethodTrouble.lookup(java.lang.Integer)
at java.lang.Class.getMethod(Class.java:1605)
at MethodTrouble.main(MethodTrouble.java:12)
$ java MethodTrouble lookup java.lang.Object Found: public void MethodTrouble.lookup(T)
Когда метод будет объявлен с универсальным типом параметра, компилятор заменит универсальный тип своей верхней границей, в этом случае, верхней границей T Object. Таким образом, когда код ищет lookup(Integer), никакой метод не находится, несмотря на то, что экземпляр MethodTrouble создавался следующим образом:
Class<?> c = (new MethodTrouble<Integer>()).getClass();
Поиск lookup(Object) успешно выполняется как ожидалось.
$ java MethodTrouble find java.lang.Integer
Found:
public void MethodTrouble.find(java.lang.Integer)
$ java MethodTrouble find java.lang.Object
java.lang.NoSuchMethodException: MethodTrouble.find(java.lang.Object)
at java.lang.Class.getMethod(Class.java:1605)
at MethodTrouble.main(MethodTrouble.java:12)
В этом случае, find() не имеет никаких универсальных параметров, таким образом, типы параметра, разыскиваемые должен соответствовать точно.
бросается, если попытка предпринимается, чтобы вызвать a private или иначе недоступный метод.
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
class AnotherClass {
private void m() {}
}
public class MethodTroubleAgain {
public static void main(String... args) {
AnotherClass ac = new AnotherClass();
try {
Class<?> c = ac.getClass();
Method m = c.getDeclaredMethod("m");
// m.setAccessible(true); // solution
Object o = m.invoke(ac); // IllegalAccessException
// production code should handle these exceptions more gracefully
} catch (NoSuchMethodException x) {
x.printStackTrace();
} catch (InvocationTargetException x) {
x.printStackTrace();
} catch (IllegalAccessException x) {
x.printStackTrace();
}
}
}
Трассировка стека для выданного исключения следует.
$ java MethodTroubleAgain
java.lang.IllegalAccessException: Class MethodTroubleAgain can not access a
member of class AnotherClass with modifiers "private"
at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:65)
at java.lang.reflect.Method.invoke(Method.java:588)
at MethodTroubleAgain.main(MethodTroubleAgain.java:15)
private методы в отдельном class и открытые методы в отдельном частном class.) Однако, Method как объявляют, расширяется AccessibleObject который обеспечивает возможность подавить эту проверку через . Если это успешно выполнится, то последующие вызовы этого объекта метода не перестанут работать из-за этой проблемы. был retrofitted, чтобы быть методом переменной арности. Это - огромное удобство, однако оно может привести к неожиданному поведению. может привести к запутывающим результатам.
import java.lang.reflect.Method;
public class MethodTroubleToo {
public void ping() { System.out.format("PONG!%n"); }
public static void main(String... args) {
try {
MethodTroubleToo mtt = new MethodTroubleToo();
Method m = MethodTroubleToo.class.getMethod("ping");
switch(Integer.parseInt(args[0])) {
case 0:
m.invoke(mtt); // works
break;
case 1:
m.invoke(mtt, null); // works (expect compiler warning)
break;
case 2:
Object arg2 = null;
m.invoke(mtt, arg2); // IllegalArgumentException
break;
case 3:
m.invoke(mtt, new Object[0]); // works
break;
case 4:
Object arg4 = new Object[0];
m.invoke(mtt, arg4); // IllegalArgumentException
break;
default:
System.out.format("Test not found%n");
}
// production code should handle these exceptions more gracefully
} catch (Exception x) {
x.printStackTrace();
}
}
}
$ java MethodTroubleToo 0 PONG!
Начиная со всех параметров являются дополнительными за исключением первого, они могут быть опущены, когда у метода, который будет вызван, нет никаких параметров.
$ java MethodTroubleToo 1 PONG!
Код в этом случае генерирует это предупреждение компилятора потому что null неоднозначно.
$ javac MethodTroubleToo.java MethodTroubleToo.java:16: warning: non-varargs call of varargs method with inexact argument type for last parameter; m.invoke(mtt, null); // works (expect compiler warning) ^ cast to Object for a varargs call cast to Object[] for a non-varargs call and to suppress this warning 1 warning
Не возможно определить ли null представляет пустой массив параметров или первого параметра null.
$ java MethodTroubleToo 2
java.lang.IllegalArgumentException: wrong number of arguments
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke
(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke
(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at MethodTroubleToo.main(MethodTroubleToo.java:21)
Это перестало работать несмотря на то, что параметр null, потому что тип является a и ping() не ожидает параметров вообще.
$ java MethodTroubleToo 3 PONG!
Это работает потому что new Object[0] создает пустой массив, и к varargs методу, это эквивалентно не передаче любого из дополнительных параметров.
$ java MethodTroubleToo 4
java.lang.IllegalArgumentException: wrong number of arguments
at sun.reflect.NativeMethodAccessorImpl.invoke0
(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke
(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke
(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at MethodTroubleToo.main(MethodTroubleToo.java:28)
В отличие от предыдущего примера, если пустой массив сохранен в , тогда это обрабатывается как . Это перестало работать по той же самой причине что случай 2 сбоя, ping() не ожидает параметр.
foo(Object... o) объявляется компилятор поместит все параметры, к которым передают foo() в массиве типа . Реализация foo() то же самое, как будто оно было объявлено foo(Object[] o). Понимание этого может помочь избежать типов проблем, иллюстрированных выше. обертки все исключения (проверенный и непроверенный) произведенный, когда объект метода вызывается.
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class MethodTroubleReturns {
private void drinkMe(int liters) {
if (liters < 0)
throw new IllegalArgumentException("I can't drink a negative amount of liquid");
}
public static void main(String... args) {
try {
MethodTroubleReturns mtr = new MethodTroubleReturns();
Class<?> c = mtr.getClass();
Method m = c.getDeclaredMethod("drinkMe", int.class);
m.invoke(mtr, -1);
// production code should handle these exceptions more gracefully
} catch (InvocationTargetException x) {
Throwable cause = x.getCause();
System.err.format("drinkMe() failed: %s%n", cause.getMessage());
} catch (Exception x) {
x.printStackTrace();
}
}
}
$ java MethodTroubleReturns drinkMe() failed: I can't drink a negative amount of liquid
InvocationTargetException бросается, метод был вызван. Диагноз проблемы был бы тем же самым, как будто метод вызвали непосредственно и выдал исключение, которое получается . Это исключение не указывает на проблему с отражательным пакетом или его использованием.