- 概念:
程序在运行时,会动态加载类进入内存,然后产生一个Class类型的对象,其中包含了完整的类结构信息,通过该Class对象可以访问到JVM中的这个类。(反射机制的功能是:动态获取信息以及动态调用对象方法)
如下图示类的正常加载情况,(以student类为例)
- Class对象获取:
- 对象.getClass()
- 类.class()
- Class.forName(“所有的包名.类名”) 动态加载类,最常用的
- 通过反射获取信息:
-
获取构造器:
public Constructor[] getConstructors()://所有公有构造方法
public Constructor[] getDeclaredConstructors();//所有构造方法 -
获取成员变量
所有成员变量:getFields();
getDeclaredFields();
指定的成员变量:getField(String name)
getDeclaredField(String name) -
获取成员方法:
所有方法:getMethods();
getDeclaredMethods();
指定的方法:getMethods(String name, Class<?>…parameterTypes);
getDeclaredMethods(String name, Class<?>…parameterTypes); --第一个参数是调用的方法名称,后面的都是方法的形参类型(如String.class / int.class …)。
-
调用方法
Method --> public Object invoke(Object obj,Object… args): // 动态代理,可以节省很多不必要的操作
参数说明:
obj : 要调用方法的对象;
args:调用方式时所传递的实参
例:Object result = m.invoke(obj, 20); -
创建(实例化)对象
1) 使用Class对象的newInstance()方法来创建该Class对象对应类的实例(这种方式要求该Class对象的对应类有默认构造器). 例如,Object targetObject = clazz.newInstance();
2) 先使用Class对象获取指定的Constructor对象, 再调用Constructor对象的newInstance()方法来创建该Class对象对应类的实例(通过这种方式可以选择指定的构造器来创建实例).
例如,Object obj = stuClass.getConstructor().newInstance();静态加载和动态加载的区别
静态加载(需要重新编译):
//获取User的实例对象
User user = new User();动态加载(不需要重新编译):
//newInstance() 获取User的实例化对象
try {
Class c3 = Class.forName(“java_reflex.User”);
c3.newInstance();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} -
反射的作用
1) 通过反射动态获取一个类的构造方法、成员变量、方法。。。
2) 结合配置文件使用,可以使程序更加灵活
3) 反射可以消除泛型在编译器的类型检查 -
反射的应用场景
当我们不确定要创建的实例的目标类具体是哪个类,就需要动态的通过反射来创建。
同理,当我们不确定具体应用那个方法的时候,我们不可能把它写死,一定要采用动态的方式,需要用什么的时候,就调用什么,这个时候就用上了反射来获取方法。