【java】反射

828 阅读2分钟

想要了解反射,首先得先了解下一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));
            }
        }
    }
}

}