JAVA反射机制的作用体现在两点:
对于任意一个类,都能够知道这个类的所有属性和方法;
对于任意一个对象,都能够调用它的任意一个方法和属性;
这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
除了int等基本类型外,Java的其他类型全部都可以认为是class(包括interface)。
由于JVM为每个加载的class创建了对应的Class实例,并在实例中保存了该class的所有信息,包括类名、包名、父类、实现的接口、方法、字段等,因此,如果获取了实例对应的Class实例,就可以通过这个Class实例获取到该实例对应的class的所有信息。
// 以String为例
//方法一:直接通过一个class的class静态变量获取
Class class1 = String.class;
//方法二:通过实例变量提供的getClass()方法获取
String s = "";
Class class2 = s.getClass();
//方法三:如果知道一个class的完整类名,可以通过静态方法Class.forName()获取:
Class class3 = Class.forName("java.lang.String");
访问字段
对任意的一个实例,只要我们获取了它的Class,就可以获取它的一切信息。
Class类提供了以下几个方法来获取字段:
Field getField(name):根据字段名获取某一个public权限的字段(包括父类)
Field getDeclaredField(name):根据字段名获取当前类的某一个public权限的字段(不包括父类)
Field[] getFields():获取public权限的所有字段(包括父类)
Field[] getDeclaredFields():获取当前类的所有字段(不包括父类)
这里只展示单个字段的获取
public class Main {
public static void main(String[] args) throws Exception {
//获取Student的Class实例
Class stdClass = Student.class;
// 获取Student的public字段"score":
System.out.println(stdClass.getField("score"));
// 获取Student父类的public字段"name":
System.out.println(stdClass.getField("name"));
// 获取Student的private字段"grade":
System.out.println(stdClass.getDeclaredField("grade"));
}
}
class Student extends Person {
public int score;
private int grade;
}
class Person {
public String name;
}
输出结果
public int one.Student.score public java.lang.String one.Person.name private int one.Student.grade
若使用stdClass.getField(“grade”)获取private字段,则会报错如
Exception in thread "main" java.lang.NoSuchFieldException: grade at java.lang.Class.getField(Class.java:1703) at one.Main.main(Main.java:xx)访问方法
Class实例获取所有Field对象,同样的,可以通过Class实例获取所有方法。Class类提供了以下几个方法来获取方法:
Method getMethod(name, Class…):获取某一个public方法(包括父类)
Method getDeclaredMethod(name, Class…):获取当前类的某一个方法(不包括父类)
Method[] getMethods():获取所有public的方法(包括父类)
Method[] getDeclaredMethods():获取当前类的所有方法(不包括父类)
使用方法和访问字段相同,就不多展示
但调用非public方法时虽然可以通过Class.getDeclaredMethod()获取该方法实例,但直接对其调用将得到一个IllegalAccessException。为了调用非public方法,我们通过Method.setAccessible(true)允许其调用:
public class Main {
public static void main(String[] args) throws Exception {
Person person = new Person();
// 获取Person的Class实例
Class class1 = person.getClass();
// 获取Class实例的方法
Method m = class1.getDeclaredMethod("setName", String.class);
// 允许对private进行操作
m.setAccessible(true);
// 执行person的方法
m.invoke(person, "Bob");
//验证操作是否成功
System.out.println("personName = " + person.name);
}
}
class Person {
String name;
private void setName(String name) {
this.name = name;
}
}
personName = Bob访问构造方法
如果通过反射来创建新的实例,可以调用Class提供的newInstance()方法:
Person p = Person.class.newInstance();
但它只能调用该类的public无参数构造方法。如果构造方法带有参数,或者不是public,就无法直接通过Class.newInstance()来调用。
为了调用任意的构造方法,Java的反射API提供了Constructor对象,包含一个构造方法的所有信息,可以创建一个实例。Constructor对象和Method非常类似,不同之处仅在于它是一个构造方法,并且,调用结果总是返回实例:
通过Class实例获取Constructor的方法如下:
getConstructor(Class…):获取某个public的构造方法;
getDeclaredConstructor(Class…):获取某个构造方法;
getConstructors():获取所有public的构造方法;
getDeclaredConstructors():获取所有构造方法。



