java可变参数反射_java反射调用可变长度参数的方法

在java中可以用可变长度参数,这样可以给调用者更大的灵活度,可变长度参数在编译后就是一个数组参数,不用担心可变长度参数是null的问题,不传的话就是一个长度为0的数组,可变长度参数只能是最后一个参数。

但是在用反射调用有可变长度参数的方法时要注意,如下图:

public String testa(Object... args){

for (Object arg : args) {

System.out.println(arg);

}

return "a";

}

@Test

public void test28() throws InvocationTargetException, IllegalAccessException {

Method method = ReflectionUtil.getMethodByName(NormalTest.class, "testa");

//报错 argument type mismatch

// method.invoke(this, 123);

//报错 argument type mismatch

// method.invoke(this, new Object[]{123});

//报错 wrong number of arguments

// method.invoke(this, new Object[]{123, 456});

//报错 argument type mismatch

// method.invoke(this, new Object[]{new int[]{123, 456}});

//正确

method.invoke(this, new Object[]{new Integer[]{123, 456}});

}

从上面看出参数要被包成数组2次,至于为什么2次不明白。

但是下面的例子又说明参数包装成1次也是可以的,如下:

public String testa(int a, int b) {

System.out.println(a + b);

return "testa";

}

public String testb(int... a){

for (int i : a) {

System.out.println(i);

}

return "testb";

}

public String testc(int a, int b, int... c){

System.out.println(a + b);

for (int i : c) {

System.out.println(i);

}

return "testc";

}

@Test

public void test28() throws InvocationTargetException, IllegalAccessException {

Method testa = ReflectionUtil.getMethodByName(NormalTest.class, "testa");

//参数个数固定,直接给参数

System.out.println(testa.invoke(this, 1, 2));

Method testb = ReflectionUtil.getMethodByName(NormalTest.class, "testb");

//方法参数是可变参数,需要包2层数组

System.out.println(testb.invoke(this, new Object[]{new int[]{1,2}}));

//正确,和上面结果一样,但是有的情况下需要包2层数组,这个包一层也可以,不知道原因

System.out.println(testb.invoke(this, new int[]{1,2}));

//直接给参数,报wrong number of arguments

// System.out.println(testb.invoke(this, 1, 2));

//报错 argument type mismatch

// System.out.println(testb.invoke(this, 1));

Method testc = ReflectionUtil.getMethodByName(NormalTest.class, "testc");

//正确

System.out.println(testc.invoke(this, 1, 2, new int[]{1, 2}));

//报错 argument type mismatch

System.out.println(testc.invoke(this, 1, 2, new Object[]{new int[]{1,2}}));

}

为什么通过反射就要包装成数组,甚至包装2次,不明白。

参考这个作者的回答:https://stackoverflow.com/questions/53694634/call-variable-argument-method-by-reflection

Method.invoke(object, Object...)本身就需要将所有参数封装成一个Object数组,而方法可变长度参数也只是数组参数的语法糖而已,因此要想通过反射调用testa(Object... args)即test(Object[] args)就必须用new Object[]{new Object[]{}},最外层Object数组是给Method.invoke用的,最里层数组是你的方法需要的参数。

再说另一个问题,数组是可以协变的,即Object[] objects = new Integer[1];是合法的,但是Object[] objects = new int[1];或Integer[] ints = new int[1];是非法的。

在调用可变长度参数时,如果你给的参数类型和方法参数类型相同或可协变的或者可转换的,则直接把你的参数转换后传递给方法参数,如果不能转换,会在外层包装一层Object数组,把你的参数作为Object数组中的元素传给方法参数。看下图:

public String testa(Object... args){

for (Object arg : args) {

System.out.println(arg);

}

return "a";

}

public String testb(int... args){

for (Object arg : args) {

System.out.println(arg);

}

return "b";

}

@Test

public void test28() throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {

this.testa(123);

//int[]不能转换成Object[],因此会被包在Object[]里面

this.testa(new int[]{123});

//这种写法和上面是一样的

this.testa(new Object[]{new int[]{123}});

this.testa(new Integer[]{123});

this.testa(new Object[]{123});

System.out.println("======");

this.testb(123);

//int[]能直接转换为方法需要的参数

this.testb(new int[]{123});

//编译报错

// this.testb(new Integer[]{123});

}

打印的结果是

123

[I@783e6358

[I@17550481

123

123

======

123

123

疑问:

public void testa(Object... args){

}

public void testa(Object[] args){

}

在编译后都会变成testa(Object[] args)这种形式,为什么在调用的时候testa()调用可变长度参数方法编译通过,调用数组参数编译报错,是在javac的过程中检查方法参数类型做转换吗?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值