通过Java发射机制调用可变参数函数
1、获取可变参数的函数
获取可变参数的函数与获取参数类型为数组类型一样。 clazz.getMethod("test", Object[].class);
其中Object为可变参数或者数组的数据类型
例如:
public void test(String ... params){
...
}
则获取该可变参数的函数如下:
Class clazz = Class.forName("com.demo003.MainThread");
Method method = clazz.getMethod("test", String[].class);
2、执行调用带有可变参数的函数
此时,我们应该如何将多个参数值传给可变参数呢?
method.invoke(obj , new String[]{"a" ,"b" ,"C"}) ,
或者是
method.invoke(mainThread, "a" ,"b" ,"c" );
这样调用对吗?
以上两种方式的调用会报:Exception in thread "main" java.lang.IllegalArgumentException: wrong number of arguments
是不是感觉挺奇怪的?
其实Method的invoke方法的参数也是一个可变参数,如下是invoke的定义
那么当参数new String[]{"a" ,"b" ,"C"})传给invoke方法时,会自动拆分成3个参数:"a" ,"b" ,"c" ,那么invoke方法自然认为目标调用函数是带有3个形参的,
所以invoke方法调用目标函数时,会将这3个参数传递给目标函数,而目标函数仅仅是一个可变参数而已,所以就发生参数个数不一致的问题。对于反射来说,
是通过将数组类型对象传递给目标函数的可变参数的,即它只需要将多个参数组成一个数组,然后将这个数组传递给可变参数,然后目标函数的可变参数再自动将这个数组值自动拆分成多个参数值。
那么我们应该如何传呢?
既然知道了如果数组类型与invoke函数的参数类型(为Object)可以转换,并且为一维数组时,它会自动拆分成多个参数,导致最终参数个数不一致而出现异常。
同时知道了反射是通过将数组对象传递给目标函数的可变参数的。那么也就以意味这个,可以将这个需要传递数组类型对象转换invoke方法不可转换拆分的对象即可。
解决方案如下:
1)将数据类型对象强制转换成一个Object类型对象,这样就不会进行自动拆分了
method.invoke((Object) new String[]{"a" ,"b" ,"C"})
2)将当前数组再包装成一个一维数组,从而达到拆分出来的是一个数组对象
Object[]p = new Object[]{ new String[]{"a" ,"b" ,"C"} }
method.invoke(p)
可能还有其他的解决方案,只要最终达到invoke不能拆分该数组参数,或者是拆分后也只有该数组对象这个参数即可