类的反射机制

在java中,类、接口、Enum等编译后,都会生成.class文件,用来记录每一个类的具体信息。在加载.class文件时,JVM会产生一个Class实例来代表该.class文件,Class实例记录了每一个类的所有信息。通多Class实例,我们就可以实现反射机制了。
可以通过三种方法来获得java.lang.Class的实例

  1. 通过对象的成员函数getClass()来获得,该函数为java.lang.Object类的public函数,由于每一个类都是继承Object的,所以每一个类都会有该函数
  2. 通过类名.class来获得。
  3. 通过Class.forName()来获得。Class.forName有两个版本,Class.forName("类名")Class.forName("类名", bool值是否加载初始化,类加载器)

对于基本类型,也可以使用对应打包类上加.TYPE来取得Class对象,例如:
使用Integer.TYPE可取得代表int基本类型的Class,如果需要取得代表Integer.class文档的Class,那么必须使用Integer.class.

拥有Class实例后,就可以通过Class实例所记录的信息来获得对应类的信息以及生成类实例。可以得到类的所有构造方法、成员函数(包括静态方法)以及成员属性(包括静态属性),还可以访问以及修改对象的私有成员属性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package chb.test.reflect;

public class Student {
private int age;
private String name;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}

public static void hi(int age,String name){
System.out.println("大家好,我叫"+name+",今年"+age+"岁");
}
}
调用方法

在方法调用中,参数类型必须正确,这里需要注意的是不能使用包装类替换基本类型,比如不能使用Integer.class代替int.class

1
2
3
4
5
6
7
8
Class cls = Class.forName("chb.test.reflect.Student");
Method m = cls.getDeclaredMethod("hi",new Class[]{int.class,String.class});
m.invoke(cls.newInstance(),20,"chb");

//static方法调用时,不必得到对象
Class cls = Class.forName("chb.test.reflect.Student");
Method staticMethod = cls.getDeclaredMethod("hi",int.class,String.class);
staticMethod.invoke(cls,20,"chb");//这里不需要newInstance

private的成员变量赋值

如果直接通过反射给类的private成员变量赋值,是不允许的,这时我们可以通过setAccessible方法解决。代码示例:

1
2
3
4
5
6
Class cls = Class.forName("chb.test.reflect.Student");
Object student = cls.newInstance();
Field field = cls.getDeclaredField("age");
field.setAccessible(true);//设置允许访问
field.set(student, 10);
System.out.println(field.get(student));

其实,在某些场合下(类中有get,set方法),可以先反射调用set方法,再反射调用get方法达到如上效果,代码示例:

1
2
3
4
5
6
7
8
Class cls = Class.forName("chb.test.reflect.Student");
Object student = cls.newInstance();

Method setMethod = cls.getDeclaredMethod("setAge",Integer.class);
setMethod.invoke(student, 15);//调用set方法

Method getMethod = cls.getDeclaredMethod("getAge");
System.out.println(getMethod.invoke(student));//再调用get方法

以上的代码来自这里