下面例子列出了在反射类中可能会遇到的典型问题。
编译告警:“注意:…使用未受检异常或者不安全操作”
当一个方法被调用,则它的参数值被校验并可能被转换。ClassWarning调用getMethod()来造成典型未受检版本告警:
import java.lang.reflect.Method;
public class ClassWarning{
void m(){
try{
Class c = ClassWarning.class;
Method m = c.getMethod("m");
}catch(NoSuchMethodException x){
x.printStackTrace();
}
}
}
$ javac ClassWarning.java
Note: ClassWarning.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
$ javac -Xlint:unchecked ClassWarning.java
ClassWarning.java:6: warning: [unchecked] unchecked call to getMethod
(String,Class<?>...) as a member of the raw type Class
Method m = c.getMethod("m"); // warning
^
1 warning
许多库方法使用泛型声明来改进,包括Class中的方法。由于 c被声明为原型类(没有形参)并且 getMethod()是一个参数化类型,一个受检异常发生,编译器需要一个泛型告警。
有两种方法可以解决,比较受欢迎的方法是添加合适的泛型来修改c的声明,在这个例子中,如:
Class<?> c = warn.getClass();
相反,使用注解@SuppressWarning处理这个问题时,告警会被隐藏。
Class c = ClassWarning.class
@SuppressWarnings("unchecked")
Method m = c.getMethod("m");
构造方法不可访问异常(InstantiationException when the Constructor is Not Accessible)
Class.newInstance()将抛出一个InstantiationException异常,如果试图构建一个对象并且没有无参构造方法,类ClassTrouble例子阐述了结果栈信息:
class Cls{
private Cls(){}
}
public class ClassTrouble{
public static void main(String ... args){
try{
Class<?> c = Class.forName("Cls");
c.newInstance();
}catch(InstantiationException x){
x.printStackTrace();
}catch(IllegalAccessException x){
x.printStackTrace();
}catch(ClassNotFoundException x){
x.printStackTrace();
}
}
}
$ java ClassTrouble
java.lang.IllegalAccessException: Class ClassTrouble can not access a member of
class Cls with modifiers "private"
at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:65)
at java.lang.Class.newInstance0(Class.java:349)
at java.lang.Class.newInstance(Class.java:308)
at ClassTrouble.main(ClassTrouble.java:9)
Class.newInstance()行为和new关键字非常相似,new方法也会因为同样的原因失败。在反射中,典型的解决方法是充分利用java.lnag.reflect.AccessibleObject类,它提供能够限制访问控制校验,然而,这种方式不能使用,因为java.lang.Class没有继承AccessibleObject,仅有的解决方法是将代码修改为Constructor.newInstance(),它不需要继承AccessibleObject.