当前位置: 首页 > 图灵资讯 > 技术篇> Java反射 Reflection

Java反射 Reflection

来源:图灵教育
时间:2023-09-03 17:02:17

Java 详细说明反射机制 | JavaGuide(Java面试 + 学习指南)

Java反射的优缺点【Java面试】 (qq.com)

Java中的反射是什么? (qq.com)

口语回答

反射是Java语言的一个重要特征。它可以在程序运行过程中构建任何类对象,获得任何类对象的变量、方法和属性,并调用任何对象。

成员变量与属性的区别:

Person类中定义了三个字段 age、name、gender是类成员的变量,但它们并不都是属性;属性是什么?

属性的定义规则如下:set/get方法名,去掉set/get后,将首字母小写剩余部分获得的字符串就是这一类的属性。

Java语言通过反射能力支持动态获取程序信息和动态调用方法的能力。

Java中有一个专门的Java.lang.reflect用于实现与反射相关的类库,包括construct、Field、Method等类分别用于获取类别的结构方法、成员变量和方法信息。

反射的使用场景相当多,比如在动态代理场景中,使用动态生成的代理来提高代码的重用性。在Spring框架中,反射被广泛使用,例如反射被用来实例Bean对象。

Java反射的优点:

  • 增加程序的灵活性。在操作过程中可以动态修改和操作类别
  • 例如,动态代理使用反射来提高代码的重用率
  • 在运行过程中,可以轻松获得任何类的方法和属性,也可以通过反射动态调用

Java反射的缺点:

  • 反射可能涉及动态类型的分析,因此JVM无法优化这些代码,导致性能低于非反射调用
  • 使用反射后,代码的可读性会下降
  • 反射可以绕过一些限制访问的属性或方法,可能会破坏代码本身的抽象性。
获取Class对象的四种方式

1 如果你知道具体的类别,你可以使用它

Class alunbarClass = TargetObject.class;

但是,我们一般不知道具体的类别,基本上是通过遍历包下面的类别获得的 Class 通过这种方式获得对象 Class 对象不会初始化

2 通过Class.forName()获取传入类的全路径

Class alunbarclass1 = Class.forName("cn.javaguide.TargetObject");

3 instance通过对象实例.getClass()获取

TargetObject o = new TargetObject();Class alunbarclass2 = o.getClass();

4 xxclassloder通过类加载器.loadClass()获取传入类路径:

ClassLoader.getSystemClassLoader().loadClass("cn.javaguide.TargetObject");

Class对象不会通过类加载器初始化,这意味着不会执行一系列步骤,包括初始化,静态代码块和静态对象不会执行。

一些基本的反射操作

1 创建一个我们需要使用反射操作的类别 TargetObject

package cn.javaguide;public class TargetObject {    private String value;    public TargetObject() {        value = "JavaGuide";    }    public void publicMethod(String s) {        System.out.println("I love " + s);    }    private void privateMethod() {        System.out.println("value is " + value);    }}

2 使用反射操作和参数的方法

package cn.javaguide;import java.lang.reflect.Field;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;public class Main {    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchFieldException {        /**         * 获取 TargetObject 类的 Class 并创建对象 TargetObject 类实例         */        Class<?> targetClass = Class.forName("cn.javaguide.TargetObject");        TargetObject targetObject = (TargetObject) targetClass.newInstance();        /**         * 获取 TargetObject 所有定义类别的方法         */        Method[] methods = targetClass.getDeclaredMethods();        for (Method method : methods) {            System.out.println(method.getName());        }        /**         * 获取指定的方法并调用         */        Method publicMethod = targetClass.getDeclaredMethod("publicMethod",                String.class);        publicMethod.invoke(targetObject, "JavaGuide");        /**         * 获取指定参数并修改参数         */        Field field = targetClass.getDeclaredField("value");        ///为了修改类中的参数,我们取消了安全检查        field.setAccessible(true);        field.set(targetObject, "JavaGuide");        /**         * 调用 private 方法         */        Method privateMethod = targetClass.getDeclaredMethod("privateMethod");        ///为了调用private,我们取消了安全检查        privateMethod.setAccessible(true);        privateMethod.invoke(targetObject);    }}
原理?

通过类加载器将类字节码文件加载到内存中,并生成相应的Class对象。通过Class对象,可以获取和操作各种信息,实现动态调用和操作。

Java反射的运行机制如下:

  1. 类加载:Java程序执行时,类加载器根据类名查找并加载相应的类文件,将字节码文件加载到内存中,生成相应的Class对象。

  2. 获取Class对象:通过类加载器加载类别后,可以通过Class.forName()方法或对象的getclass()方法获取相应的class对象。

  3. 获取类结构信息:类结构函数、方法、字段等信息可以通过Class对象获取。通过Class获取Constructor()、getMethod()和getfield()等方法,可获得指定的结构函数、方法和字段。

  4. 动态调用:通过Method对象的invoke(),可以动态调用类的方法。通过Field对象的get()和set(),可以访问和修改类的字段。

例如应用场景
  1. 框架和库:Springg等许多开源框架和库、Hibernate、Junit等,都使用反射来实现自动化配置、动态代理、对象关系映射等功能。

  2. 注释处理器:注释处理器可以通过反射进行分析和处理,生成相应的代码或实现特定的功能。例如,Java编译器的注释处理器可以通过反射进行扫描和处理。

  3. 序列化和反序列化:Java的序列化和反序列化机制可以通过反射读取和写入对象的属性,实现对象的序列化和反序列化。

  4. 配置文件的分析和加载:许多应用程序使用配置文件来配置参数和设置,可以动态地读取和分析配置文件,并根据配置文件的内容加载相应的类别和执行相应的操作。

  5. 动态代理:动态代理是通过反射实现的,可以在运行过程中动态生成代理类,并在代理类中调用代理对象的方法。

  6. 测试工具和单元测试:测试工具和单元测试框架可通过反射动态调用测试方法,实现自动测试和测试结果的收集。

  7. 动态加载类和资源:通过反射,可以在运行过程中动态加载类和资源文件,实现类的动态加载和更新。