# 反射的概述

  • 反射是框架设计的灵魂。
  • 反射是一种在运行时动态获取类的信息并操作类的属性、方法和构造函数的技术。
  • 它允许程序在运行时动态地获取类的信息并操作类的属性、方法和构造函数等。

# 反射的简介

  • 反射是 Java 编程语言中一种强大的机制,它允许程序在运行时动态地获取类的信息并操作类或对象。
  • 通过反射,我们可以在运行时获取类的属性、方法、构造函数等,并且可以动态调用这些成员。
  • 这种能力使得我们可以在事先不知道类的情况下,通过运行时获取类的信息并进行相关操作。
  • Java 反射提供了以下几个重要的类和接口:
    • Class 类:它是反射的核心类,代表了一个类的信息,可以获取类的属性、方法、构造函数等。
    • Field 类:它表示类的成员变量(属性),可以通过它获取和设置成员变量的值。
    • Method 类:它表示类的方法,可以通过它调用类的方法。
    • Constructor 类:它表示类的构造函数,可以通过它创建类的实例。
  • 通过反射,我们可以实现一些灵活的功能,比如动态创建对象、调用私有方法、访问私有属性等。
  • 但需要注意的是,由于反射涉及到底层的操作,使用不当可能会影响性能,并且也会破坏了面向对象的封装性。

# 反射的原理

反射机制的实现依赖于 Java 的类加载机制。 在 Java 中,每个类都必须通过 ClassLoader 类来加载,而 ClassLoader 类又分为三种类型: BootStrap ClassLoaderExtension ClassLoaderApplication ClassLoader 。当一个类被加载时, Java 虚拟机会根据类的全限定名找到相应的 ClassLoader 来加载类文件,并将其转换为 Class 对象。

# 反射应用场景

  • 例如:
    • 动态创建对象:通过反射机制可以在运行时动态地创建对象,而不需要提前知道类的具体信息。
    • 动态调用方法:通过反射机制可以在运行时动态地调用对象的方法,而不需要提前知道方法的具体名称和参数。
    • 获取类的属性和方法:通过反射机制可以在运行时动态地获取类的属性和方法,包括属性的名称、类型、修饰符等等。
    • 操作类的注解:通过反射机制可以获取类的注解信息,并进行相应的处理。
    • 实现代理和适配器:通过反射机制可以动态地生成代理和适配器,实现对现有类的扩展和修改。
  • 由于反射机制需要在运行时动态地获取类的信息,因此会带来一定的性能开销和安全风险。
  • 反射机制虽然强大,但也有一些限制和缺,此外,反射机制也容易被误用,导致代码难以维护和调试。

# 反射使用步骤

  1. 获取 Class 对象:使用 Class.forName()ClassLoader.loadClass() 方法获取一个类的 Class 对象。
  2. 获取类的成员信息:使用 Class 类的 getDeclaredFields()getDeclaredMethods()getDeclaredConstructors() 方法获取类的成员信息,包括字段、方法和构造方法。
  3. 访问类的成员:使用 Class 类的 getField()getMethod()getConstructor() 方法获取类的成员对象,然后使用成员对象的相应方法访问类的属性、方法和构造函数。
  4. 调用类的方法:使用 Method 类的 invoke() 方法调用类的方法,并传递相应的参数。
  5. 创建类的实例:使用 Class 类的 newInstance() 方法创建类的实例。

# 反射的使用

# 反射获取字段

Person.java
/**
 * @Author: LightRain
 * @Description: Bean 对象
 * @DateTime: 2023-08-29 18:08
 * @Version:1.0
 **/
public class Person {
    private String name;
    private int age;
    private String address;
}
ReflectDemo.java
/**
 * @Author: LightRain
 * @Description: 使用反射获取 Bean 对象中的字段
 * @DateTime: 2023-08-29 16:04
 * @Version:1.0
 **/
public class ReflectDemo {
    public static void main(String[] args) {
        // 获取一个类的所有属性
        Class<?> clazz = Person.class;
        // 获取声明字段
        Field[] fields = clazz.getDeclaredFields();
        // 遍历所有属性并打印出它们的名称
        for (Field field : fields) {
            System.out.println(field.getName());
        }
    }
}

# 反射获取 Get 方法

Person.java
/**
 * @Author: LightRain
 * @Description: Bean 对象
 * @DateTime: 2023-08-29 18:08
 * @Version:1.0
 **/
public class Person {
    private String name;
    private int age;
    private String address;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getAddress() {
        return address;
    }
    public void setAddress(String address) {
        this.address = address;
    }
}
ReflectDemo.java
/**
 * @Author: LightRain
 * @Description: 使用反射获取 Bean 对象中的所有 get 方法和参数
 * @DateTime: 2023-08-29 16:04
 * @Version:1.0
 **/
public class ReflectDemo {
    public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        // 创建对象并设置参数
        Person person = new Person();
        person.setName("张三");
        person.setAge(16);
        person.setAddress("...");
        // 获取一个类中所有的 get 方法
        Class<?> clazz = Person.class;
        Method[] methods = clazz.getDeclaredMethods();
        Method[] getMethods = Arrays.stream(methods)
                .filter(method -> Modifier.isPublic(method.getModifiers()) && method.getReturnType() != void.class && method.getName().startsWith("get"))
                .toArray(Method[]::new);
        // 调用每个 get 方法
        for (Method method : getMethods) {
            Object result = method.invoke(person);
            System.out.println(method.getName() + " = " + result);
        }
    }
}