Java反射获取方法以及调用方法
获取方法
先找到方法所在类的字节码
找到需要被获取的方法
Class类中获取方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
//获取包括自身和继承(实现)过来的所有的public方法——Method不支持泛型<>,即后面不接<>
public Method[] getMethods();
//获取自身所有的方法(private、public、protected,和访问权限无关),不包括继承的
public Method[] getDeclaredMethods();
//表示获取指定的一个公共的方法,包括继承的
public Method[] getMethod(String methodName, Class<T>...parameterTypes);
参数: methodName:表示获取的方法的名字
parameterTypes:表示获取的方法的参数的Class类型
//表示获取本类中的一个指定的方法(private、protected、public,与访问权限无关),不包括继承的方法
public Method[] getDeclaredMethod(String methodName, Class<T>...parameterTypes);
|
通过反射调用方法:
先找到方法所在类的字节码
找到需要被获取的方法
调用该方法
1
2
3
4
5
6
7
8
9
|
class User{
public void sayHello(){...}
public void sayHi(String naem){...}
private void sayGoodBye(String name, int age){...}
}
|
如何使用反射调用一个方法?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
//表示调用当前Method所表示的方法
public Object invoke(Object obj, Object... args);
参数: obj: 表示被调用方法底层所属对象
args: 表示调用方法时传递的实际参数
返回:方法调用后,底层方法的返回结果
Eg:
public String sayYa(String name){....}
Class<User> clz=User.class;
Method mt=clz.getMethod(“sayYa”, String.class);
Object obj=clz.newInstance();
Object ret=mt.invoke(obj, “wili”);
//要调用实例方法,必须有一个对象,方法的底层对象就是指当前Method所在的类的实例对象,
sayHi方法具有返回值,调用该方法后的返回结果使用Object接收
|
调用私有方法:
1
2
3
4
5
6
|
Method mt=clz.getDeclaredMethod(“sayGoodBye”, String.class, int.class);
//在调用私有方法之前,需设置该方法为可访问的权限:——否则会报错
mt.setAccessible(true);
mt.invoke(clz.newInstance(), “limi”, 17);
|
调用静态方法
1
2
3
4
5
6
7
8
9
10
|
class User{
public static void staticMethod(){
System.out.println(“static mthod invoke.”);
}
}
Eg:
Class<User> clz=User.class;
Method staticMethod=clz.getMethod(“staticMthod”);
|
两种方式调用静态方法:
因为静态方法属于所有实例对象公共的,可以创建该类的一个任意对象,通过该对象调用
1
2
|
//staticMethod无参,故参数列表类型不填
staticMethod.invoke(clz.newInstance());
|
如果底层方法是静态的,那么可以忽略指定的obj参数,将obj参数设置为null即可
1
|
staticMethod.invoke(null);
|
使用反射调用可变参数的方法
1
2
3
4
5
6
7
8
9
|
class User{
public static int sum(int... ages){
System.out.println(args);//打印结果可看出:可变参数底层就是一个数组
Int sum=0;
for(int i : args){
Sum+=i;
}
return sum;
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
public static void show(String... args){...}
}
Eg:
Class<User> clz=User.class;
//可变参数底层就是一个数组
Method m=clz.getMethod(“sum”, int[].class);
M.invoke(null, new int[]{1,2,3});
Method m=clz.getMethod(“show”, String[].class);
//会报错,可变参数是引用类型时,底层会自动解包,
上述调用被解包后变成M.invoke(null,“A”,”B”,”C”);
——为了解决该问题,我们再使用一层数组把实际参数包装起来
M.invoke(null, new String[]{“A”,”B”,”C”});
//正确
M.invoke(null, new Object[]{new String[]{“A”,”B”,”C”}});
|
通用方法:
以后在使用反射调用invoke方法时,在传递实际参数的时候,无论是基本数据类型,还是引用类型,或者是可变参数类型,把实际参数都包装在一维数组中。
1
2
3
4
5
6
7
8
9
10
11
12
|
m.invoke(方法的底层对象,new Object[]{实际参数});
Eg:
//方法参数为基本类型,且只有一个参数,解包后变成m.invoke(null,17});
m.invoke(null, new Object[]{17});
//方法参数为String类型,且只有一个参数
m.invoke(null, new Object[]{“xxx”});
//方法参数为int类型,且为可变参数或者数组类型
m.invoke(null, new Object[]{new int[]{1,2}});
//方法参数为String类型,且为可变参数或者数组类型,
new String[]{“A”,”B”}为传递的实际参数
m.invoke(null, new Object[]{new String[]{“A”,”B”}});
|