现在我们继续学习反射。
我们甘愿忍受眼下的痛苦,是因为我们没有别的选择。
通过Class实例调用方法
Class类提供了以下几个方法来获取Method:
- Method getMethod(name, Class…):获取某个public的Method(包括父类)
- Method getDeclaredMethod(name, Class…):获取当前类的某个Method(不包括父类)
- Method[] getMethods():获取所有public的Method(包括父类)
- Method[] getDeclaredMethods():获取当前类的所有Method(不包括父类)
public class Main {
public static void main(String[] args) throws Exception {
Class stdClass = Student.class;
// 获取public方法getScore,参数为String:
System.out.println(stdClass.getMethod("getScore", String.class));
// 获取继承的public方法getName,无参数:
System.out.println(stdClass.getMethod("getName"));
// 获取private方法getGrade,参数为int:
System.out.println(stdClass.getDeclaredMethod("getGrade", int.class));
}
}
class Student extends Person {
public int getScore(String type) {
return 99;
}
private int getGrade(int year) {
return 1;
}
}
class Person {
public String getName() {
return "Person";
}
}
上述代码首先获取Student的Class实例,然后,分别获取public方法、继承的public方法以及private方法
一个Method对象包含一个方法的所有信息:
- getName():返回方法名称,如:“getScore”;
- getReturnType():返回方法返回值类型,也是一个Class实例,如:String.class;
- getParameterTypes():返回方法的参数类型,是一个Class数组,如:{String.class, int.class};
- getModifiers():返回方法的修饰符,它是一个int。
调用方法
当我们到一个Method对象时,就可以对它进行调用了。
public class Main {
public static void main(String[] args) throws Exception {
// String对象:
String s = "Hello world";
// 获取String substring(int)方法,参数为int:
Method m = String.class.getMethod("substring", int.class);
// 在s对象上调用该方法并获取结果:
String r = (String) m.invoke(s, 6);//从第六个的位置开始输出
// 打印调用结果:
System.out.println(r);
//结果为:world
}
}
调用静态方法
如果获取到的Method表示一个静态方法,调用静态方法时,由于无需指定实例对象,所以invoke方法传入的第一个参数永远为null。
public class Main {
public static void main(String[] args) throws Exception {
// 获取Integer.parseInt(String)方法,参数为String:
Method m = Integer.class.getMethod("parseInt", String.class);
// 调用该静态方法并获取结果:
Integer n = (Integer) m.invoke(null, "12345");
// 打印调用结果:
System.out.println(n);
}
}
对于Method的invoke方法实现,大家可以去看看这篇博客,里面有具体的解释,我感觉写的很好
https://blog.csdn.net/wenyuan65/article/details/81145900
调用非public方法
和Field类似,对于非public方法,我们虽然可以通过Class.getDeclaredMethod()获取该方法实例,但直接对其调用将得到一个IllegalAccessException。为了调用非public方法,我们通过Method.setAccessible(true) 允许其调用
public class Main {
public static void main(String[] args) throws Exception {
Person p = new Person();
Method m = p.getClass().getDeclaredMethod("setName", String.class);
m.setAccessible(true);
m.invoke(p, "Bob");
System.out.println(p.name);
}
}
class Person {
String name;
private void setName(String name) {
this.name = name;
}
}
获取继承关系
获取父类Class
有了 Class 实例,我们还可以获取它的父类的 Class:
public class Main {
public static void main(String[] args) throws Exception {
Class i = Integer.class;
Class n = i.getSuperclass();
System.out.Println(n);
Class o = n.getSuperclass();
System.out.println(o);
System.out.println(o.getSuperclass());
}
}
运行上述代码,可以看到,Integer的父类类型是Number,Number的父类是Object,Object的父类是null。除Object外,其他任何非interface的Class都必定存在一个父类类型。
获取接口
由于一个类可能实现一个或多个接口,通过Class我们就可以查询到实现的接口类型。例如,查询Integer实现的接口:
public class Main {
public static void main(String[] args) throws Exception {
Class s = Integer.class;
Class[] is = s.getInterfaces();
for (Class i : is) {
System.out.println(i);
}
}
}
运行上述代码可知,Integer实现的接口有:
java.lang.Comparable
java.lang.constant.Constable
java.lang.constant.ConstantDesc
关于Class类的还涉及到多态,向上转型。这些可以去我的另外一篇博客看看。三大特征
大家可以去看看这位博主写的,很多例子,可以让我们更好的理解
https://www.cnblogs.com/nerxious/archive/2012/12/24/2829446.html