反射报错解决 java.lang.IllegalArgumentException: wrong number of arguments

反射调用参数为数组的函数问题

java.lang.IllegalArgumentException: wrong number of arguments

问题背景:

UT执行单测遇到报错 java.lang.IllegalArgumentException: wrong number of arguments

代码

    @Test
    public void test_getAntennaTilt_when_valid_then_return_min_value() {
        AntennaMgrImpl antennaMgr = new AntennaMgrImpl();
        final Method getAntennaTilt = PowerMockito.method(antennaMgr.getClass(), "getAntennaTilt", GainParam[].class);
        getAntennaTilt.setAccessible(true);
        double result = 0d;
        GainParam[] vGains = new GainParam[]{new GainParam()};
        try {
            result = (double) getAntennaTilt.invoke(antennaMgr.getClass(), vGains);
        } catch (InvocationTargetException | IllegalAccessException e) {
            TestCase.fail();
        }
        TestCase.assertEquals(result, 0d);
    }
复制代码

报错信息

java.lang.IllegalArgumentException: argument type mismatch
​
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at
复制代码

IDEA编译器提示信息

Confusing argument 'vGains', unclear if a varargs or non-varargs call is desired
复制代码

解决方法

参数强转为Object

result = (double)getAntennaTilt.invoke(antennaMgr.getClass(), (Object) vGains);
复制代码

错误原因

当方法签名为数组时,使用反射(或通过mock等其他方式调用反射),注意参数需要将参数强转为Object,原因为invoke方法的签名为可变长参数,编译器无法确认传入的是某一个参数,还是参数列表

反射是运行时获取的,在运行时看来,可变长参数和数组是一致的,因而方法签名为:

//方法签名
([Ljava/lang/String;)V // public void foo(String[] varargs)
复制代码

当编译器发现类似

method.invoke(object, arg1, arg2) 
复制代码

这样的表示时,会隐式地创建一个数组,类似new Object [] {arg1, arg2} ,然后将该数组作为invoke方法的参数。 但是如果目标方法的参数本来就是一个数组的时候,如

1 method.invoke(object, Object[]) 
复制代码

编译器会认为你已经将所有的参数放到数组里面了,从而不会再次包装。于是在这种情况下,作为参数传递给目标方法的,其实是数组里面的元素,而不是数组本身。

总结

当用反射调用方法时,如果目标方法的入参是一个数组,则要把数组包装到另一个Object数组中。

猜你喜欢

转载自juejin.im/post/7018030594156134408