何为反射?
反射是一种动态获取运行状态的类的信息(属性和方法等)的能力。
简单说,对于Java中任何一个类,我们都可以获取它的属性和方法。
如何实现反射?
了解它之前,我们首先需要了解Java中的Class类。
http://blog.youkuaiyun.com/hyhyl1990/article/details/49227301 (Java Class类简介)
对于每一个类,初始化时Java虚拟机都会对它生成字节码(.class),我们可以通过Class类来实现动态获取和调用类的属性和方法。
通过反射调用类的方法.
使用反射调用类的方法主要是通过java.lang.reflect.Method类来实现的。
Method类提供了类或者接口的某个方法的信息(方法明,修饰符,参数等等)。既包括类的静态方法也包括实例方法(对象方法)。
获取到一个Method对象(它对应一个类的方法)后,我们可以调用method对象的invoke函数来实现对该方法的调用。
public Object invoke(Object obj, Object... args)
obj参数是调用该方法的类对象(如果是静态方法,不需要实例化类对象),args是给该方法传递的参数信息。
Demo:
我们自定义一个类MyClass2,它有如下的几种方法,我们通过反射机制逐一调用。
public class MyClass2 {
static int staticVal;
int val;
public MyClass2() {}
public MyClass2 (int val) {
this.val = val;
}
public static void staticShowVal() {
System.out.println("MyClass2 fun. static showVal null param");
System.out.println(staticVal);
}
public void showVal() {
System.out.println("MyClass2 fun. showVal null param");
System.out.println(this.val);
}
public void showVal(int val) {
System.out.println("MyClass2 fun. showVal String param");
System.out.println(val + "");
}
public void showVal(String[] vals, int[] intVals) {
System.out.println("MyClass2 fun. showVal String[] param & int[] param");
for (int i = 0; i < vals.length; i++) {
System.out.println(vals[i]);
}
for (int i = 0; i < intVals.length; i++) {
System.out.println(intVals[i]);
}
}
}
以下是使用反射进行不同的方法调用。
在使用反射进行调用之前,我们需要先获取该类的Class对象,一般可以由以下方法获得:
Class<?> class2 = null;
try {
class2 = Class.forName("com.hyl.MyClass2");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
1.调用MyClass2的静态方法
//invoke the static method
Method staticMethod = null;
try {
staticMethod = class2.getMethod("staticShowVal", null);
staticMethod.invoke(class2, null);
} catch (Exception e) {
e.printStackTrace();
}
因为是类的静态方法,所以invoke的第一个参数,我们并不需要初始化一个MyClass2的实例,直接使用我们上面得到的MyClass2类的Class对象即可。
因为要调用的方法是无参数的,所以invoke的第二个参数我们传递null即可。
2.调用MyClass2的成员方法(空参数)
Method method = null;
try {
method = class2.getMethod("showVal", null);
Object obj1 = class2.newInstance();
method.invoke(obj1, null);
} catch(Exception e) {
e.printStackTrace();
}
与调用静态方法不同,调用成员方法,我们需要首先初始化该方法所属类的一个实例,使用类的class对象的newInstance()方法即可得到一个实例化。
3.调用MyClass2的含int参数的成员方法
Method method = null;
try {
method = class2.getMethod("showVal", new Class<?>[] {int.class});
//MyClass2 must have an default null params Constructor
Object obj1 = class2.newInstance();
nt v = 3;
method.invoke(obj1, new Object[]{v});
} catch(Exception e) {
e.printStackTrace();
}
与调用空参数的方法不同,要调用带参数的成员方法,我们需要:
使用getMethod方法得到Method对象时,要传入相应的参数类型(Class数组)
使用invoke调用时也要传递相应的参数。
之前在讲解Class类时,我们有提到,每个基本数据类型也都对应有自己的Class类型。int类型对应的Class类型即是int.class.
4.调用MyClass2的含String数组int数组参数的成员方法
try {
method = class2.getMethod("showVal", new Class<?>[] {String[].class, int[].class});
Object obj1 = class2.newInstance();
String[] strArr = {"1", "2"};
int[] intArr = {1, 2};
method.invoke(obj1, new Object[]{strArr, intArr});
} catch (Exception e) {
e.printStackTrace();
}
和上面的调用基本相同,只是需要根据要调用方法的参数类型传递相应的参数。