Java 反射调用有可变参数的方法
Java 反射调用有可变参数的方法
Java 反射经常会用到,但是在反射可变参数时,写法和平时有点不同。
以下面的类作为反射对象试验:
1 | class Parameters { |
一、普通调用
1 | new Parameters().multi("1"); // 1 |
很简单,传几个参数就是几个。
二、数组传参
上面是传递的是简单的对象类型,换成数组会怎么样?
1 | String[] args = new String[]{"1", "2", "3"}; |
1 | Object[] args = new Object[]{"1", "2", "3", "4"}; |
如果传给可变参数的只是1个数组,那么这个数组不会被认为是1个参数,而是多个参数。
- 本质上,可变参数就是1个数组参数,传多个参数和只传1个数组参数,效果是一样的
- 可变参数只是 Java 语法糖,Java 会自动把参数数组拆分成多个参数
不过如果传的参数不止一个数组,就可以按正常逻辑处理:
1 | Object[] args = new Object[]{"1", "2", "3", "4"}; |
1 | Object[] args = new Object[]{"1", "2", "3", "4"}; |
由于已经明确传递了多个参数,所以第一个数组不再被认为是多个参数了。
三、错误的反射传参
一般来说,反射传参是这样写的:
1 | Method method = Parameters.class.getDeclaredMethod("multi", Object[].class); |
这个本意是传递3个参数 {“1”, “2”, “3”} 给 multi
方法,但是实际上是不行的,会报错:
1 | java.lang.IllegalArgumentException: wrong number of arguments |
这是为什么呢?
原因是可变参数本质上就只是1个数组参数而已,也就是说可变参数方法只要1个数组参数而已。
从 getDeclaredMethod("multi", Object[].class)
这里也可以看出来,参数只有1个,也就是 Object[]
。
而 method.invoke(object, "1", "2", "3")
调用实际上传给 multi
方法的参数是 3 个,而不是 1 个,所以会出现参数个数不匹配的错误。
但是,如果直接传递1个参数数组也是不行的:
1 | Method method = Parameters.class.getDeclaredMethod("multi", Object[].class); |
这个也会报一样的错误,因为 method.invoke()
接收的也是可变参数,只传1个数组和上面的传多个参数是同样的效果。
四、正确的反射传参
首先明确2件事:
method.invoke()
接收的也是可变参数,只传1个数组会被认为是多个参数- 可变参数本质上是接收1个参数数组
需要把1个数组参数传给 multi
方法,但是又不让 method.invoke()
把这个数组拆分成多个参数,怎么办呢?
正确的做法是,把数组参数再包装一层:
1 | Method method = Parameters.class.getDeclaredMethod("multi", Object[].class); |
invokeArgs
参数是给 method.invoke()
用的,methodArgs
参数是给 multi
方法用的。
invokeArgs
里面只有1个 methodArgs
,这样就不会被认为是多个参数了,只会被认为是1个数组参数。
所以最终传给 multi
的就只有1个参数 methodArgs
了。
总结
- 可变参数只是 Java 语法糖,Java 会自动把参数数组拆分成多个参数
- 可变参数只是 Java 的语法糖,本质上和1个数组参数是一样的
- 传多个可变参数,和传1个数组参数是一样的效果
- 反射可变参数的方法时,要确保传给可变参数方法的最终参数是1个数组
Java 反射调用有可变参数的方法