UPDATE -使问题更清楚。
在通过反射调用方法时获得ClassCastException的可能原因是什么?
我得到了以下堆栈跟踪作为我的应用程序的一部分,而试图通过反射调用一个方法。
java.lang.IllegalArgumentException: java.lang.ClassCastException@21fea1fv
at sun.reflect.GeneratedMethodAccessor332.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.....
(remaining is my method stack trace)
我尝试了一个示例类,并传递了不同类型的各种参数给它,但我总是得到一个this异常。
java.lang.IllegalArgumentException: argument type mismatch
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)
更新——下面是我为尝试重新创建异常
而编写的示例代码创建代理类的接口
package my.tests;
public interface ReflectionsInterface {
public abstract void doSomething();
}
这是测试类
package my.tests;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class Reflections implements ReflectionsInterface {
public static void main(String[] args) {
Reflections reflections = new Reflections();
ReflectionsInterface reflectionsProxy = reflections.createProxy(ReflectionsInterface.class);
invokeMethod(reflectionsProxy, "doSomething", null);
}
public <T> T createProxy(Class<T> entityInterface) {
EntityInvocationHandler eih = new EntityInvocationHandler(this);
T cast = entityInterface.cast(Proxy.newProxyInstance(
entityInterface.getClassLoader(), new Class[]{entityInterface}, eih));
return cast;
}
public static void invokeMethod(Object obj, String methodName, Object... args) {
Method[] methods = obj.getClass().getMethods();
try {
for (Method method : methods) {
if (method.getName().equals(methodName)) {
method.invoke(obj, args);
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void doSomething() {
System.out.println("woo");
}
private final static class EntityInvocationHandler implements InvocationHandler,
ReflectionsInterface {
private Reflections reflectionObj;
public EntityInvocationHandler(Reflections reflectionObj) {
super();
this.reflectionObj = reflectionObj;
}
@Override
public void doSomething() {
reflectionObj.doSomething();
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object invoke = method.invoke(this, args);
return invoke;
}
}
}
我无法理解何时我将得到参数类型不匹配和ClassCastException将引起。我无法重新创建异常,想知道它为什么出现。任何重新创建它的工作代码,或者在这种情况下抛出此异常的源代码引用都将是好的
我已经通过了Method.class javadocs和源代码,我无法弄清楚为什么会出现这个错误。
我通过修改示例代码重新创建了ClassCastException
:用正确的参数调用invokeMethod
10000次,然后用错误的参数调用它。
Reflections
类中的main
方法
public static void main(String[] args) {
Reflections reflections = new Reflections();
ReflectionsInterface reflectionsProxy = reflections
.createProxy(ReflectionsInterface.class);
for (int i = 0; i < 10000; i++)
invokeMethod(reflectionsProxy, ReflectionsInterface.class,
"doSomething");
invokeMethod(new Object(), ReflectionsInterface.class, "doSomething");
}
Reflections
类中的invokeMethod
方法
public static void invokeMethod(Object obj, Class<?> clazz,
String methodName, Object... args) {
Method[] methods = clazz.getMethods();
try {
for (Method method : methods) {
if (method.getName().equals(methodName)) {
method.invoke(obj, args);
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
堆栈跟踪:
java.lang.IllegalArgumentException: java.lang.ClassCastException@603a3e21
at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.twbbs.pccprogram.Reflections.invokeMethod(Reflections.java:33)
at org.twbbs.pccprogram.Reflections.main(Reflections.java:16)
我的ClassCastException
解释:
当您第一次调用invokeMethod
时,JVM使用较慢的路由,这对程序员来说更容易调试(所以它更慢!),因此当您传递一个错误的参数时,它将显示一个更友好的argument type mismatch
消息。
当您多次调用invokeMethod
时(在我的测试中16次就足够了),JVM在运行时生成一个GeneratedMethodAccessor***
,它更快,错误检查更少。因此,当您传递一个错误的参数时,它将显示这样一个丑陋的java.lang.ClassCastException@603a3e21
消息。
问题就在这里:
reflections.invokeMethod("doInt", 1L);
你正在调用doInt
,但是你传递的是long
的值。因此,反射试图将Long
转换为Integer
,这是无效的。
我怀疑你的意思是:
reflections.invokeMethod("doLong", 1L);
我稍微修改了一下你的代码来重现这个错误:
java.lang.IllegalArgumentException: argument type mismatch
界面
public interface ReflectionsInterface
{
public abstract void doSomething1(Integer i);
public abstract void doSomething2(String s);
}
在类Reflections和EntityInvocationHandler中添加方法以便编译。然后在main()中添加这个方法。执行并生成错误运行时
invokeMethod(reflectionsProxy, "doSomething1", "1");
我试图得到unclasscastexception,但我没有成功。它可能发生在原始代码中,因为有更多的对象,并且传递给方法的类型无效。添加日志并尝试调试以隔离ClassCastException。