Java 反射调用有可变参数的方法

Java 反射调用有可变参数的方法

Java 反射经常会用到,但是在反射可变参数时,写法和平时有点不同。

以下面的类作为反射对象试验:

1
2
3
4
5
class Parameters {
public int multi(Object... args) {
return args.length;
}
}

一、普通调用

1
2
3
4
5
new Parameters().multi("1"); // 1

new Parameters().multi("1", "2"); // 2

new Parameters().multi("1", "2", "3", "4"); // 4

很简单,传几个参数就是几个。

二、数组传参

上面是传递的是简单的对象类型,换成数组会怎么样?

1
2
String[] args = new String[]{"1", "2", "3"};
new Parameters().multi(args); // 3
1
2
Object[] args = new Object[]{"1", "2", "3", "4"};
new Parameters().multi(args); // 4

如果传给可变参数的只是1个数组,那么这个数组不会被认为是1个参数,而是多个参数。

  • 本质上,可变参数就是1个数组参数,传多个参数和只传1个数组参数,效果是一样的
  • 可变参数只是 Java 语法糖,Java 会自动把参数数组拆分成多个参数

不过如果传的参数不止一个数组,就可以按正常逻辑处理:

1
2
Object[] args = new Object[]{"1", "2", "3", "4"};
new Parameters().multi("0", args); // 2
1
2
Object[] args = new Object[]{"1", "2", "3", "4"};
new Parameters().multi(args, "5"); // 2

由于已经明确传递了多个参数,所以第一个数组不再被认为是多个参数了。

三、错误的反射传参

一般来说,反射传参是这样写的:

1
2
Method method = Parameters.class.getDeclaredMethod("multi", Object[].class);
method.invoke(new Parameters(), "1", "2", "3");

这个本意是传递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
2
3
Method method = Parameters.class.getDeclaredMethod("multi", Object[].class);
Object[] args = new Object[]{"1", "2", "3"};
method.invoke(new Parameters(), args);

这个也会报一样的错误,因为 method.invoke() 接收的也是可变参数,只传1个数组和上面的传多个参数是同样的效果。

四、正确的反射传参

首先明确2件事:

  1. method.invoke() 接收的也是可变参数,只传1个数组会被认为是多个参数
  2. 可变参数本质上是接收1个参数数组

需要把1个数组参数传给 multi 方法,但是又不让 method.invoke() 把这个数组拆分成多个参数,怎么办呢?

正确的做法是,把数组参数再包装一层:

1
2
3
4
Method method = Parameters.class.getDeclaredMethod("multi", Object[].class);
String[] methodArgs = new String[]{"1", "2", "3"};
Object[] invokeArgs = new Object[]{methodArgs};
method.invoke(new Parameters(), invokeArgs);

invokeArgs 参数是给 method.invoke() 用的,methodArgs 参数是给 multi 方法用的。

invokeArgs 里面只有1个 methodArgs,这样就不会被认为是多个参数了,只会被认为是1个数组参数。

所以最终传给 multi 的就只有1个参数 methodArgs 了。

总结

  • 可变参数只是 Java 语法糖,Java 会自动把参数数组拆分成多个参数
  • 可变参数只是 Java 的语法糖,本质上和1个数组参数是一样的
  • 传多个可变参数,和传1个数组参数是一样的效果
  • 反射可变参数的方法时,要确保传给可变参数方法的最终参数是1个数组

Java 反射调用有可变参数的方法

http://example.com/lang/java/other/reflect_paramters/

作者

jiaduo

发布于

2023-01-09

更新于

2023-04-02

许可协议