想要了解反射,首先得先了解下一J V M 类 加 载 流 程 和 内 存 结 构,如下图。
java源文件通过编译器加载成Class文件(包含类所有信息),然后通过ClassLoader将Class文件加载到JVM中,在内存中进行管理。
而反射就是获取这个Class文件,从而获取到类的属性,类的方法,类的字段,实现的接口等等。
我们通过下图来感受一下反射与new对象之间的区别:
new对象和反射在类加载上的区别是:new对象(RTTI)是在编译期打开和检查Class文件。而反射是在运行期打开和检查Class文件。
因次我们不难理解我们在编写业务代码时使用new对象居多,而我们所使用框架底层是使用反射居多。
这是因为当我们能够在编译期能够确定使用的对象时就使用new,而当我们在编译期间不能确定所使用的对象时,就使用反射(在运行期间将用到的对象给反射出来)。
下面,我通过伪代码给大家介绍反射的使用:
三种获得Class文件的方式:
// 方式一 类.class
Class personClazz = Person.class;
// 方式二 实例.getClass()
Person person = new Person();
Class personClazz1 = person.getClass();
// 方式三 Class.forName("类的全路径")
Class personClazz2 = Class.forName("com.muse.reflect.Person");
通过Class对象,创建构造方法对象:
//初始化无参构造方法
Constructor constructor = personClazz.getConstructor();
// 初始化有参构造方法对象
Constructor constructor1 = personClazz.getConstructor(String.class, Integer.class, Byte.class,Boolean.class);
通过构造方法创建对象:
// 调用无参数构造方法创建Person对象
Person person = (Person) constructor.newInstance();
// 调用有参数构造方法创建Person对象
Person person1 = (Person) constructor1.newInstance("无尽的蓝海", 2021, (byte) 1, true);
Class对象的一些常用方法(具体可看jdk的帮助文档): 获取成员变量:
/*
* Field[] getFields() //获取所有public修饰的成员变量
Field getField(String name) //获取指定名称的public修饰的成员变量
Field[] getDeclaredFields() //获取所有的成员变量,不考虑修饰符
Field getDeclaredField(String name) //获取指定的成员变量,不考虑修饰符
* */
获取成员方法:
/*
Method[] getMethods() 获取所有public修饰的成员方法
Method getMethod(String name, 类<?>... parameterTypes) 获取指定名称的public修饰的成员方法
Method[] getDeclaredMethods() 获取所有的成员方法,不考虑修饰符
Method getDeclaredMethod(String name, 类<?>... parameterTypes) 获取指定名称的成员方法,不考虑修饰符
*/
文末,给大家分享一个应用了反射的常用工具类(赋值工具类)
public class BeanUtils {
public static void convertor(Object originObj, Object targetObj) throws Throwable{
// 第一步,获得class对象
Class orginClazz = originObj.getClass();
Class targetClazz = targetObj.getClass();
// 第二步,获得Field
Field[] orginFields = orginClazz.getDeclaredFields();
Field[] targetFields = targetClazz.getDeclaredFields();
// 第三步:赋值
for (Field originField : orginFields) {
for (Field targetField : targetFields) {
if (originField.getName().equals(targetField.getName())) {
originField.setAccessible(true);
targetField.setAccessible(true);
targetField.set(targetObj, originField.get(originObj));
}
}
}
}
}