面试题答案
一键面试异常产生常见场景
- IllegalAccessException
- 场景一:访问权限问题:当通过反射试图访问一个类的私有方法、私有字段等,但当前代码没有足够的访问权限时会抛出此异常。例如,一个类中有私有方法
private void privateMethod()
,在外部类通过反射调用此方法时,如果没有设置setAccessible(true)
,就会抛出IllegalAccessException
。 - 场景二:类加载相关:如果加载的类字节码在安全性方面有特殊限制,比如类加载器对某些类的访问权限进行了限制,反射访问时也可能抛出此异常。
- 场景一:访问权限问题:当通过反射试图访问一个类的私有方法、私有字段等,但当前代码没有足够的访问权限时会抛出此异常。例如,一个类中有私有方法
- InvocationTargetException
- 场景一:目标方法抛出异常:当通过反射调用的目标方法本身抛出了异常时,就会被包装在
InvocationTargetException
中抛出。例如,目标方法public void divide(int a, int b)
中有return a / b;
,如果调用时b
为0,就会抛出ArithmeticException
,但在反射调用时会被包装成InvocationTargetException
。 - 场景二:方法调用过程中的错误:如果目标方法的参数类型与实际传入参数类型不匹配,虽然编译时不会报错(因为反射是动态的),但运行时会导致方法调用失败,也会抛出
InvocationTargetException
。
- 场景一:目标方法抛出异常:当通过反射调用的目标方法本身抛出了异常时,就会被包装在
定位问题根源及调试策略
- 定位IllegalAccessException问题根源及调试策略
- 检查访问权限:首先查看要访问的方法或字段的修饰符,确认是否为私有。如果是私有,检查是否调用了
setAccessible(true)
来绕过访问权限检查(在合法合规的情况下)。例如:
- 检查访问权限:首先查看要访问的方法或字段的修饰符,确认是否为私有。如果是私有,检查是否调用了
try {
Class<?> clazz = Class.forName("com.example.MyClass");
Method method = clazz.getDeclaredMethod("privateMethod");
method.setAccessible(true);
method.invoke(clazz.newInstance());
} catch (Exception e) {
e.printStackTrace();
}
- 检查类加载器和安全策略:查看类加载的上下文,是否存在特殊的安全策略限制。可以通过打印类加载器信息,例如
System.out.println(clazz.getClassLoader());
,检查类加载器是否有特殊配置。如果存在安全策略问题,可能需要调整安全策略文件或检查安全管理器的设置。
- 定位InvocationTargetException问题根源及调试策略
- 获取目标异常:
InvocationTargetException
包含了目标方法抛出的原始异常,可以通过调用getCause()
方法获取。例如:
- 获取目标异常:
try {
// 反射调用方法
Object result = method.invoke(obj, args);
} catch (InvocationTargetException e) {
Throwable cause = e.getCause();
cause.printStackTrace();
// 根据具体的异常类型进行分析,如ArithmeticException等
} catch (Exception e) {
e.printStackTrace();
}
- 检查参数类型:确认反射调用时传入的参数类型是否与目标方法的参数类型匹配。可以打印参数类型信息进行比对,例如:
for (Object arg : args) {
System.out.println(arg.getClass());
}
Method method = clazz.getMethod("methodName", arg1.getClass(), arg2.getClass());
同时,也要检查方法签名中声明的异常类型,确保调用者能够正确处理可能抛出的异常。