invoke
public Object invoke(Object obj, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException
对带有指定参数的指定对象调用由此 Method
对象表示的底层方法。个别参数被自动解包,以便与基本形参相匹配,基本参数和引用参数都随需服从方法调用转换。
参数:obj
- 从中调用底层方法的对象args
- 用于方法调用的参数
返回:
使用参数 args
在 obj
上指派该对象所表示方法的结果
抛出:IllegalAccessException
- 如果此 Method
对象强制执行 Java 语言访问控制,并且底层方法是不可访问的。IllegalArgumentException
- 如果该方法是实例方法,且指定对象参数不是声明底层方法的类或接口(或其中的子类或实现程序)的实例;如果实参和形参的数量不相同;如果基本参数的解包转换失败;如果在解包后,无法通过方法调用转换将参数值转换为相应的形参类型。InvocationTargetException
- 如果底层方法抛出异常。NullPointerException
- 如果指定对象为 null,且该方法是一个实例方法。ExceptionInInitializerError
- 如果由此方法引起的初始化失败。
如果底层方法是静态的,那么可以忽略指定的 obj
参数。该参数可以为 null。
如果底层方法所需的形参数为 0,则所提供的 args
数组长度可以为 0 或 null。
如果底层方法是实例方法,则使用动态方法查找来调用它,这一点记录在 Java Language Specification, Second Edition 的第 15.12.4.4 节中;在发生基于目标对象的运行时类型的重写时更应该这样做。
如果底层方法是静态的,并且尚未初始化声明此方法的类,则会将其初始化。
如果方法正常完成,则将该方法返回的值返回给调用者;如果该值为基本类型,则首先适当地将其包装在对象中。但是,如果该值的类型为一组基本类型,则数组元素不 被包装在对象中;换句话说,将返回基本类型的数组。如果底层方法返回类型为 void,则该调用返回 null。
既然是讲invoke方法,那就不讲怎么使用反射了,请看例子:
package com.chenjie.core; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import org.junit.Test; public class TestInvoke { public void test(String[] arg){ for (String string : arg) { System.out.println(string); } } @Test public void demo1() throws Exception { //获取字节码对象 Class<TestInvoke> clazz = (Class<TestInvoke>) Class.forName("com.chenjie.core.TestInvoke"); //获取一个对象 Constructor con = clazz.getConstructor(); TestInvoke m = (TestInvoke) con.newInstance(); String[] s = new String[]{"aa","bb"}; //获取Method对象 Method method = clazz.getMethod("test", String[].class); //调用invoke方法来调用 method.invoke(m, s); } }
测试会报错:
红色框框显示是参数错误,test方法需要是字符串数组啊,我传递也是字符串数组,怎么就不对了??
让我们来看一下invoke方法:
invoke方法的参数,一个是Object类型,也就是调用该方法的对象,
第二个参数是一个可变参数类型,这个可变参数类型怎么能传递给一个数组类型呢?一个是多个参数。一个是一个数组参数,显然参数的个数不匹配,怎么解决呢?
解决办法就是将可变参数变成一个参数:
- 将传递进去的s强转为Object类型
- 将s重新包装成一个Object数组
测试一下:
package com.chenjie.core; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import org.junit.Test; public class TestInvoke { public void test(String[] arg){ for (String string : arg) { System.out.println(string); } } @Test public void demo1() throws Exception { //获取字节码对象 Class<TestInvoke> clazz = (Class<TestInvoke>) Class.forName("com.chenjie.core.TestInvoke"); //获取一个对象 Constructor con = clazz.getConstructor(); TestInvoke m = (TestInvoke) con.newInstance(); String[] s = new String[]{"aa","bb"}; //获取Method对象 Method method = clazz.getMethod("test", String[].class); //调用invoke方法来调用 //1.将传递进去的s强转为Object类型 method.invoke(m, (Object)s); //2.将s重新包装成一个Object数组 method.invoke(m, new Object[]{s}); } }