网站做收录要多少长时间,微商目前十大火爆产品,茶业网站设计方案,app设计网站推荐调用方法
我们已经能通过Class实例获取所有Field对象#xff0c;同样的#xff0c;可以通过Class实例获取所有Method信息。Class类提供了以下几个方法来获取Method#xff1a;
Method getMethod(name, Class...)#xff1a;获取某个public的Method#xff08;包括父类同样的可以通过Class实例获取所有Method信息。Class类提供了以下几个方法来获取Method
Method getMethod(name, Class...)获取某个public的Method包括父类Method getDeclaredMethod(name, Class...)获取当前类的某个Method不包括父类Method[] getMethods()获取所有public的Method包括父类Method[] getDeclaredMethods()获取当前类的所有Method不包括父类
我们来看一下示例代码
// reflection
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类似
public int Student.getScore(java.lang.String)
public java.lang.String Person.getName()
private int Student.getGrade(int)一个Method 对象包含一个方法的所有信息
getName()返回方法名称例如“getScore”getReturnType()返回方法返回值类型也是一个Class实例例如String.classgetParameterTypes()返回方法的参数类型是一个Class数组例如{String.class, int.class}getModifiers()返回方法的修饰符它是一个int不同的bit表示不同的含义。
调用方法
当我们获取到一个Method对象时就可以对它进行调用。我们以下面的代码为例
String s Hello world;
String r s.substring(6); // world如果用反射来调用substring方法需要以下代码
// reflection
import java.lang.reflect.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);}
}
注意到substring()有两个重载方法我们获取的是String substring(int)这个方法。思考一下如何获取String substring(int, int)方法。
对Method实例调用invoke就相当于调用该方法invoke的第一个参数是对象实例即在哪个实例上调用该方法后面的可变参数要与方法参数一致否则将报错。
调用静态方法 如果获取到的Method表示一个静态方法调用静态方法时由于无需指定实例对象所以invoke方法传入的第一个参数永远为null。我们以Integer.parseInt(String)为例
// reflection
import java.lang.reflect.Method;
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);}
}
调用非public方法
和Field类似对于非public方法我们虽然可以通过Class.getDeclaredMethod()获取该方法实例但直接对其调用将得到一个IllegalAccessException。为了调用非public方法我们通过Method.setAccessible(true)允许其调用
// reflection
import java.lang.reflect.Method;
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;}
}
此外setAccessible(true)可能会失败。如果JVM运行期存在SecurityManager那么它会根据规则进行检查有可能阻止setAccessible(true)。例如某个SecurityManager可能不允许对java和javax开头的package的类调用setAccessible(true)这样可以保证JVM核心库的安全。
多态
我们来考察这样一种情况一个Person类定义了hello()方法并且它的子类Student也覆写了hello()方法那么从Person.class获取的Method作用于Student实例时调用的方法到底是哪个
// reflection
import java.lang.reflect.Method;
public class Main {public static void main(String[] args) throws Exception {// 获取Person的hello方法:Method h Person.class.getMethod(hello);// 对Student实例调用hello方法:h.invoke(new Student());}
}class Person {public void hello() {System.out.println(Person:hello);}
}class Student extends Person {public void hello() {System.out.println(Student:hello);}
}
运行上述代码发现打印出的是Student:hello因此使用反射调用方法时仍然遵循多态原则即总是调用实际类型的覆写方法如果存在。上述的反射代码
Method m Person.class.getMethod(hello);
m.invoke(new Student());实际上相当于
Person p new Student();
p.hello();小结
Java的反射API提供的Method对象封装了方法的所有信息
通过Class实例的方法可以获取Method实例getMethod()getMethods()getDeclaredMethod()getDeclaredMethods()通过Method实例可以获取方法信息getName()getReturnType()getParameterTypes()getModifiers()通过Method实例可以调用某个对象的方法Object invoke(Object instance, Object… parameters)通过设置setAccessible(true)来访问非public方法通过反射调用方法时仍然遵循多态原则。