反射是框架设计的灵魂,通过反射我们可以在程序运行时读取配置文件动态的创建一个类,也可以通过读取注解来达到我们想到的功能。与反射有关的类是Class类。
Class类对象的获取方法
Class类对象的获取方法有三种
- Class.forName(String name)
- 参数是类的全类名(包名+类名),可以获得该类的Class对象
 
 - 类名.class
- 通过类的静态属性class可以获取Class对象
 
 - 对象.getClass()
- 通过对象的getClass()方法可以获取Class对象
 
 
假设一个Animal类
public class Animal {  | 
现在要通过上面的三种方法获取该类的Class对象
//通过全类名获取Class对象  | 
另外需要注意的是,通过上面三种方法获取的Class对象是同一个对象
System.out.println(cls1 == cls2); //true  | 
Class类的常见成员方法
与成员变量有关的方法
- getFields()
- 获取public修饰的所有成员变量,返回一个Field[]
 
 - getField(String name)
- 获取指定名称被public修饰的成员变量
 
 - getDeclaredFields()
- 同getFields(),不过任意修饰符修饰的都可以获取
 
 - getDeclaredField(String name)
- 同getField(String name),不过任意修饰符修饰的都可以获取
 
 
Field[] fields1 = cls1.getFields();  | 
可以通过set(Object obj, Object value)方法对指定的对象设定值,也可以通过get(Object obj)方法来获取值
Field field2 = cls1.getDeclaredField("name");  | 
如果我们要对age进行赋值,因为age变量是private修饰的,是不能在类外面直接访问的,我们可以调用setAccessible(true)方法,来忽略访问修饰符的安全检查(暴力反射)
Field field1 = cls1.getDeclaredField("age");  | 
与构造方法有关的方法
- getConstructors()
- 得到由public修饰的所有构造方法
 
 - getConstructor()
- 获取指定参数的构造函数,如
- getConstructor():获取无参构造函数
 - getConstructor(String.class, int.class):获得第一个参数类型为String类型和第二个参数类型为int类型的构造方法
 
 
 - 获取指定参数的构造函数,如
 - cls1.getDeclaredConstructors()
- 参照Field
 
 - cls1.getDeclaredConstructor()
- 参照Field
 
 
//获得无参的构造方法  | 
现在获得了构造方法,那么构造方法的作用就是创造对象,我们可以通过Contructor对象的的newInstance()方法创建一个对象,如
//newInstance方法返回的是一个Object对象  | 
输出为
Animal{name='null', age=0}  | 
如果想创建一个无参的对象,可以直接通过Class对象的newInsatance()方法创建,如
Animal animal3 = (Animal) cls1.newInstance();  | 
与成员方法有关的方法
- getMethods
- 获取所有public修饰的方法
 
 - getMethod()
- 通过方法名和参数类型(区别重载的方法)获取public修饰的指定方法
 
 - getDeclaredMethods
- 忽略修饰符
 
 - getDeclaredMethod
- 忽略修饰符
 
 
//获取不带参数的eat方法  | 
获取到了方法,那么接下来就是怎么使用的问题,我们可以使用invoke()方法来执行方法,需要传入相应的对象和需要的参数,如果方法不需要参数,那么可以不传,如
eat1.invoke(animal);  | 
输出为
eat ...  | 
我们还可以通过getName()方法获得方法名,如
System.out.println(eat1.getName()); //eat  | 
我们可以通过Class对象的getName()方法获得该类的全类名(包名+类名)
System.out.println(cls1.getName()); //Animal  | 
使用反射读取配置文件动态创建任意的对象
我们现在有这么一个需求,那就是希望创建任意一个类的对象,并且调用相应的方法,要求不能更改代码,而只需要更改配置文件即可。现在我们创建一个config.properties的配置文件,内容如下
className=Animal  | 
我们要做的就是读取配置文件,然后根据配置文件创建相应类的对象并且调用其方法
import java.io.FileNotFoundException;  | 
现在我们运行一下
eat ...  | 
现在我们要创建什么类的对象并且要调用什么方法,只需要修改配置文件就可以了,不用修改代码了。虽然还有很多的问题,比如只能使用无参构造方法创建对象,只能调用无参的方法,不过即使是这样也让我们感受到了反射的强大。











