Java反射(Reflection)是指在运行时动态获取类的信息并操作类或对象的机制。通过反射,程序可以在运行时检查类、接口、字段和方法,并且可以实例化对象、调用方法、访问或修改字段值。

反射的核心类

Java反射的核心类位于java.lang.reflect包中,主要包括如下类:

  • Class:表示类的元数据(如类名、方法、字段等);

  • Field:表示类的字段(成员变量);

  • Method:表示类的方法;

  • Constructor:表示类的构造方法;

  • Modifier:提供对类和成员修饰符(如publicprivate等)的解析。

反射的工作原理

反射的核心是通过Class对象获取类的元数据,然后动态操作类的成员。以下是反射的基本流程:

获取Class对象

  • 通过类的全限定名获取:

    Class<?> clazz = Class.forName("com.example.MyClass");
  • 通过对象的getClass()方法获取:

    Class<?> clazz = myObject.getClass();
  • 通过类字面常量获取:

    Class<?> clazz = MyClass.class;

获取类的元数据

  • 获取字段:

    Field[] fields = clazz.getDeclaredFields(); // 获取所有字段(包括私有字段)
    Field field = clazz.getField("fieldName"); // 获取指定字段(仅公共字段)
  • 获取方法:

    Method[] methods = clazz.getDeclaredMethods(); // 获取所有方法(包括私有方法)
    Method method = clazz.getMethod("methodName", parameterTypes); // 获取指定方法
  • 获取构造方法:

    Method[] methods = clazz.getDeclaredMethods(); // 获取所有方法(包括私有方法)
    Method method = clazz.getMethod("methodName", parameterTypes); // 获取指定方法

动态操作

  • 创建对象

    Object instance = clazz.newInstance(); // 调用无参构造方法创建对象
    Object instance = constructor.newInstance(args); // 调用指定构造方法创建对象
  • 调用方法

    method.invoke(instance, args); // 调用方法
  • 访问或修改字段

    field.setAccessible(true); // 设置私有字段可访问
    field.set(instance, value); // 修改字段值
    Object value = field.get(instance); // 获取字段值

反射的底层实现

Java反射的底层实现依赖于JVM(Java虚拟机)的类加载机制和元数据管理。

  • 类加载:当调用Class.forName()getClass()时,JVM会加载类的字节码到内存中,并生成对应的Class对象;

  • 元数据存储:JVM在加载类时,会将类的元数据(如字段、方法、构造方法等)存储在方法区(Method Area)中;

  • 动态调用:反射通过JVM提供的本地方法(Native Method)访问这些元数据,并动态调用方法或访问字段。

反射的优点

  • 灵活性:可以在运行时动态加载类、调用方法、访问字段,适合框架和工具的开发;

  • 通用性:可以编写通用的代码,适用于不同类型的对象;

  • 扩展性:支持插件化开发和动态加载外部类。

反射的缺点

  • 性能开销:反射操作比直接调用方法或访问字段慢,因为涉及JVM的底层操作;

  • 安全性问题:反射可以访问私有成员,破坏了封装性;

  • 代码可读性差:反射代码通常难以理解和维护。

反射的应用场景

  • 框架开发:如Spring、Hibernate等框架利用反射实现依赖注入、对象关系映射等功能;

  • 动态代理:通过反射实现动态代理(如java.lang.reflect.Proxy);

  • 测试工具:单元测试框架(如JUnit)利用反射调用测试方法;

  • 配置文件解析:通过反射动态加载配置文件中指定的类或方法。

示例代码

import java.lang.reflect.Method;

public class ReflectionExample {
    public static void main(String[] args) throws Exception {
        // 获取Class对象
        Class<?> clazz = Class.forName("com.example.MyClass");

        // 创建对象
        Object instance = clazz.newInstance();

        // 获取方法
        Method method = clazz.getMethod("sayHello", String.class);

        // 调用方法
        method.invoke(instance, "World");
    }
}

class MyClass {
    public void sayHello(String name) {
        System.out.println("Hello, " + name);
    }
}