10

更新- 使问题更清楚。

通过反射调用方法时获得 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)

我尝试了一个示例类并将不同类型的各种参数传递给它,但我总是得到一个这个异常。

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 和源代码,我无法弄清楚为什么会出现这个错误。

4

3 回答 3

16

ClassCastException我通过修改您的示例代码重新创建了:invokeMethod用正确的参数调用 10000 次,然后用错误的参数调用它。

类中的main方法Reflections

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");
}

类中的invokeMethod方法Reflections

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 次就足够了),JVMGeneratedMethodAccessor***会在运行时生成一个,速度更快,错误检查更少。所以java.lang.ClassCastException@603a3e21当你传递一个糟糕的论点时,它会显示出如此丑陋的信息。

于 2013-04-22T13:32:27.970 回答
1

好吧,这就是问题所在:

reflections.invokeMethod("doInt", 1L);

您正在调用doInt,但您正在传递一个long值。所以反射试图将 aLong转换为 a Integer,这是无效的。

我怀疑你的意思是:

reflections.invokeMethod("doLong", 1L);
于 2013-04-16T16:49:15.040 回答
0

我对您的代码进行了一些修改以重现此错误:

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");

我试图获得 un ClassCastException 但我没有成功。它可能出现在您的原始代码中,因为有更多对象并且将无效类型传递给该方法。添加日志并尝试调试以隔离 ClassCastException。

于 2013-04-20T10:56:12.030 回答