java的反射机制到底是做什么的?

时间:2022-07-23
本文章向大家介绍java的反射机制到底是做什么的?,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

背景

在学习java的动态代理的时候用到了反射机制,那我们来对反射机制深入了解一下

权威指南

通过wiki百科可知: 在计算机学中,反射(英语:reflection)是指计算机程序在运行时(runtime)可以访问、检测和修改它本身状态或行为的一种能力。[1]用比喻来说,反射就是程序在运行的时候能够“观察”并且修改自己的行为。

在类型检测严格的面向对象的编程语言如Java中,一般需要在编译期间对程序中需要调用的对象的具体类型、接口、字段和方法的合法性进行检查。反射技术则允许将对需要调用的对象的信息检查工作从编译期间推迟到运行期间再现场执行。这样一来,可以在编译期间先不明确目标对象的接口名称、字段(fields,即对象的成员变量)、可用方法,然后在运行根据目标对象自身的信息决定如何处理。它还允许根据判断结果进行实例化新对象和相关方法的调用。

个人理解

在一般情况下, 文件会在编译期转换为jvm可执行的字节码 .class 文件,这个执行过程是在类加载的时候执行的,但是jvm在类加载对这一过程并不严格,所以说这一加载步骤可以放在运行期执行。利用这一特性也就有了反射机制。

反射机制很重要的一点就是“运行时”,其使得我们可以在程序运行时加载、探索以及使用编译期间完全未知的 .class 文件。换句话说,Java 程序可以加载一个运行时才得知名称的 .class 文件,然后获悉其完整构造,并生成其对象实体、或对其 fields(变量)设值、或调用其 methods(方法)。

我感觉还有有点“干" ,反射也是创建对象的一种方式,使用new 关键字可以创建一个对象,那是因为我们知道他是个什么对象,而反射反射的意思是,我并不知道这个对象是什么,但是我可以通过class.forName()读取到这个对象,然后也可以读取到他的Method ,interface ,Construct等,还可以通过Invoke()方法进行赋值等操作。

java中反射的使用

  1. 写一个demo
package reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @Author:yuanxindong
 * @Date:2020/5/1113:23
 */
public class Person extends Huaman{

    private  String name;
    private  String gender;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + ''' +
                ", gender='" + gender + ''' +
                '}';
    }

    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //通过classLoad 获取类的 Class 对象实例。
        Class c = Class.forName("reflect.Person");
        //根据Class对象实例获取 Constructor 对象
        Method setName = c.getMethod("setName", String.class);
        //根据 Class 对象实例获取 Constructor 对象
        Constructor constructor = c.getConstructor();
        //使用Constructor对象的newInstance 方法获取反射类对象
        Object o = constructor.newInstance();
        //使用invoke方法调用创建实例对象的方法。
        setName.invoke(o,"yuanxindong");
        //查看调用是否成功
        System.out.println(o.toString());

    }
}
  1. 下面是执行结果。

上面的代码就可以看出来java中的反射基础使用,但是一个new关键字和直接一个set方法就能解决的问题为什么,非要使用反射呢?

  • 先明确一点,反射直接根据文件的地址获取class,将其加载到内存中 。不需要在刚开始进行编译,直接在运行期间进行读取加载。 这就是他的优势,我们使用new关键字这个类必须是被预先被加载过的,我们可以大概看一forName()的源码:

其中的classLoad也就是父类加载器,我们在这里就先证明他就是去加载class对象了。(具体不在这里细究)。如果是使用new 关键字的话那么这个对象前提得是被解析过的(加载,验证,初始化和卸载这五个阶段顺序是确定的,类的加载过程必须按照这种顺序按部就班的开始,而解析阶段却不一定:他在某些情况下可以在初始化之后再开始《深入理解java虚拟机》)

  • 再者就是Java反射现在应用的场景,
    1. JDBC的数据库连接
    2. Spring 框架的使用
      1. 将程序内所有 XML 或 Properties
      2. 配置文件加载入内存中 Java类里面解析xml或properties里面的内容,得到对应实体类的字节码字符串以及相关的属性信息
      3. 使用反射机制,根据这个字符串获得某个类的Class实例
    3. 再在这里扯一下Spring为什么这么做呢?他的意思就是遵循“好莱坞规则”我不去找你,而是我来找你。也就是IOC和DI的意思,将对象创建好注入到IOC容器再使用依赖注入的方式主动注入到对应的类中。

总结

说了上面那么一大堆,也不知道吧反射机制说清楚没有, java的反射的目的就是在运行时期动态加载class对象和实例化对象,主要使用的方法有:

Class.forName();
class.getMethod();
class.getConstructor();
constructor.newInstance();
method.invoke(Object,value);

思考

我们在使用携程的文件配置系统 APollo的时候,他是如何达到更改配置后达到热更新的?是否基础原理也是用到了反射??