1. 获取和操作类方法
- 获取和操作类方法分为三个步骤:
- 首先获取目标类的字节码文件
- 然后获取字节码对象中的目标类方法
- 最后通过类对象来调用目标类方法
1.1. Class 类中获取类方法的方法
1.1.1. getMethods() 方法
定义:
public Method[] getMethods()
作用:
返回该类中所有public
方法, 并以Method
数组的形式返回.
这些public
方法包含从父类和接口中所继承的方法.
1.1.2. getDeclaredMethods() 方法
定义:
public Method[] getDeclaredMethods()
作用:
返回该类中所有方法, 并以Method
数组的形式返回, 无视访问权限进行获取.
但这些方法并不包含从父类或接口中所继承的方法.
1.1.3. getMethod(String name, Class<?>... parameterTypes) 方法
定义:
public Method getMethod(String name, Class<?>... parameterTypes)
作用:
获取该类中所指定的一个public
方法, 获取方法的范围包括从父类或接口中继承的.参数:
- name - 方法名
- parameterTypes - 参数表中参数的
Class
类型
1.1.4. getDeclaredMethod(String name, Class<?>... parameterTypes) 方法
定义:
public Method getMethod(String name, Class<?>... parameterTypes)
作用:
获取该类中所指定的一个方法, 无视访问权限获取,
但获取方法的范围不包括从父类或接口中继承的.参数:
- name - 方法名
- parameterTypes - 参数表中参数的
Class
类型
1.2. Method 类中操作类方法的方法
java.lang.reflect.Method
- 该类也有从父类中继承控制访问权限的方法, 操作和构造器中的相似.
1.2.1. invoke(Object obj, Object... args) 方法
定义:
public Object invoke(Object obj, Object... args)
作用:
对带有指定参数的指定对象调用由此Method
对象表示的底层方法.参数:
- obj - 从中调用底层方法的对象
- args - 用于方法调用的参数
返回:
使用参数 args 在 obj 上指派该对象所表示方法的结果, 以Object
的形式返回.备注:
- 如果底层方法是静态的, 那么可以忽略指定的 obj 参数. 该参数可以为 null.
- 如果底层方法所需的形参数为 0, 则所提供的 args 数组长度可以为 0 或 null.
1.3. Method 操作方法补充
1.3.1. 使用反射调用数组参数方法
假设存在如下方法
public static void test(int...arr){}
方法中参数表存在可变参数, 实际可变参数是数组,
所以需要按照如下方式进行获取和调用方法.Method m = cls.getMethod("test", int[].class); m.invoke(null, new int[] {1, 2, 3});
如果以这种方式传递参数:
m.invoke(null, 1, 2, 3);
也会报错, 因为传递的参数必须严格按照规则来传递,
可变参数实际本身是数组, 因此必须传递数组.然而对于有的数据类型的数组会被自动解包, 例如
String
类型.
假设存在如下方法:public static void te5t(String[] arr){}
获取方法后如果进行如下参数传递, 会发生错误.
Method m1 = cls.getMethod("te5t", String[].class); m1.invoke(null, new String[] {"1", "3"});
这是因为这个数组被自动解包了, 导致其恢复成一个个单独的元素.
因此会被视为传入的是一个个String
元素, 而非数组元素, 导致错误.解决方案:
由于
invoke()
方法中第二个参数是Object
可变参数,
即实际上第二个参数要求传入的是Object
类型的数组.所以可以将数据都包装进
Object
数组中, 再进行传递.
这样传递绝对符合要求, 不会发生错误.Method m1 = cls.getMethod("te5t", String[].class); m1.invoke(null, new Object[] {new String[] {"1", "3"}}); Method m = cls.getMethod("test", int[].class); m.invoke(null, new Object[] {new int[] {1, 2, 3}});
因此调用带有数组参数的方法的时候都建议统一使用这种形式传参.
1.3.2. 使用反射获取泛型参数方法
- 泛型会自动提升为
Object
类型, 因此获取的时候以Object
类型看待. - 例如存在如下包含泛型参数的方法:
public static <T> void t3st(T... arr){}
- 获取该方法时, 直接使用
Object
类型即可.Method m2 = cls.getMethod("t3st", Object[].class);