------- android培训、java培训、期待与您交流! ----------
反射机制:java在运行状态中,对于任意一个类,都能够指导着各类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性,这种动态获得的信息以及动态调用对象的方法的功能称为java语言的反射机制。
1、应用背景
假设我们有一个可以运行的程序,我们想要扩展它的功能,可是我们不能获得他的源代码。该怎么办呢?程序对外提供了一个接口,我们可以提供一个实现该接口的扩展功能类,那么要怎么让程序使用这个类呢?这就用到了java反射机制。
应用程序会对外提供一个配置文件,我们把这个扩展功能类的类名写到配置文件中,则应用程序会自动读取配置文件,并找到相应的类,执行扩展功能。
过程就是:加载类;创建类对象;调用类中的内容。
而这个过程就是java反射机制所做的内容。
Java反射机制的好处就是可以提供程序的扩展性。
2、我们对.class文件的共性进行提取,可以得到一个名为Class的类文件,类中有field字段,method方法和constructor构造器。
我们如何得到Class文件中的信息呢?
Java把Class文件封装成Class对象,并且把field字段封装成Field对象,相应的把method和constructor封装成Method和Constructor对象。
我们获取内部信息的第一步就是要获取Class对象。
3、获取Class对象
方式一:
通过对象的getClass()方法来获取。
比如有一个Person类,可以如下获取
Person p = new Person();
Class clazz = p.getClass();
方法二:
任何数据类型都有一个静态属性class,这个属性可以直接获取该类型对象的Class对象。
通过静态属性class获取。
Class clazz = Person.class;
两种方式的区别:方式一需要具体的类和该类对象还有调用getClass()方法。而方式二稍微简单一些,就是只是用具体的类和静态属性class即可。
方式三:
Java.lang包中有Class类,类中有静态方法forName(类名)。
Class clazz = Class.forName(className);
className是一个变量,我们只需要传递String类型的类名称参数即可,不需要使用类,及调用具体的属性和方法。
注意:类名称是包名+类名。否则会后报错,找不到该类。
方式三是最重要的获取Class对象的方式。
4、通过Class对象获取类实例
我们可以用Class类中的newInstance方法来创建类的实例,这时是通过调用类的空参数构造器来创建类的实例。
Object obj = clazz.newInstance();
如果我们的类中没有空参数构造器或者我们要指定参数的构造器来创建实例,该怎么办呢?
我们可以通过Class类中的getConstructor()方法来获取具体的构造器,再用Constructor类中的newInstance方法来创建实例,
Constructor constructor = clazz.getConstructor(String.class,int.class);
Object obj = constructor.newInstance("Lisi",16);
5、访问字段
import java.lang.reflect.*;
public class ReflectDemo2 {
public static void main(String[] args) throws Exception {
accessField();
}
private static void accessField() throws Exception {
//先获取Class对象
String className = "reflect.Person";
Class clazz = Class.forName(className);
//获取字段
//获取公有,私有,保护,包访问字段,不可访问继承的字段
Field field = clazz.getDeclaredField("age");
System.out.println(field);
//给字段设置值
Object obj = clazz.newInstance();
field.set(obj, 19);
System.out.println(field.get(obj));
}
}
获取字段的方法有getField(String filedName):只能获取公有和父类中的字段
getDeclaredField(String filedName):获取公有,私有,保护,包访问字段,不可访问继承的字段。
也可以给字段赋值:set(object obj,value)
获取字段对象get(Object obj)
注意:如果获取的字段是私有的话,不能访问它,解决办法是:AccessibleObject类中有setAccessible(boolean flag)方法,设为true时,可以取消访问权限,对私有字段进行访问。但不建议这么做。
6、访问方法
import java.lang.reflect.Method;
public class ReflectDemo3 {
public static void main(String[] args) throws Exception {
getMethod();
}
private static void getMethod() throws Exception {
//获取Class对象
String className = "reflect.Person";
Class clazz = Class.forName(className);
//获取方法
Method method = clazz.getDeclaredMethod("method", null);
Object obj = clazz.newInstance();
Object o = method.invoke(obj, null);
System.out.println(o);
}
}
获取字段的方法有getMethods():获取公有和父类中的方法
getDeclaredMethods():获取本类中,包括私有的方法
getMethod(String methodName,para):获取公有和父类中的方法,传入方法名称和参数
getDeclaredMethods(String methodName,para):获取本类中,包括私有的指定方法名称和传入参数的方法
获取方法对象invoke(Object obj,para)
注意:如果获取的方法是私有的话,不能访问它,解决办法是:AccessibleObject类中有setAccessible(boolean flag)方法,设为true时,可以取消访问权限,对私有方法进行访问。但也不建议这么做。
访问静态方法:
静态方法不需要创建对象,假设有一个静态的method的空参数方法。
Method method = clazz.getDeclaredMethod("method", null);
method.invoke(null, null);
这样就可以直接取出静态的方法名:method()