← 返回文章列表

Java 反射详解

java

运行时获取 Class、操作构造器、方法与字段的反射用法。

Java 反射详解

什么是反射?

反射是 Java 的动态特性,允许在运行时获取类的信息(属性、方法、构造器)并动态操作它们。

正常情况下,我们在编译时就知道要操作哪个类。反射让我们在运行时才决定操作哪个类。

获取 Class 对象的三种方式

// 方式1:通过类的 class 属性(最常用)
Class<?> clazz1 = Cat.class;

// 方式2:通过对象的 getClass() 方法
Cat cat = new Cat("三花");
Class<?> clazz2 = cat.getClass();

// 方式3:通过 Class.forName("全限定类名")
Class<?> clazz3 = Class.forName("com.example.Cat");

反射操作构造器

获取构造器

import java.lang.reflect.Constructor;

// 获取所有 public 构造器
Constructor<?>[] constructors = clazz.getConstructors();

// 获取所有构造器(包括 private)
Constructor<?>[] declaredConstructors = clazz.getDeclaredConstructors();

// 获取指定构造器
Constructor<?> constructor = clazz.getConstructor(String.class);  // 参数类型

使用构造器创建对象

// 1. 获取构造器
Constructor<?> constructor = clazz.getDeclaredConstructor(String.class);

// 2. 暴力破解:跳过权限检查(访问 private 构造器)
constructor.setAccessible(true);

// 3. 用构造器初始化对象
Object obj = constructor.newInstance("三花");  // 传入构造器参数

完整示例

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

        // 获取构造器(String 参数的构造器)
        Constructor<?> constructor = clazz.getDeclaredConstructor(String.class);

        // 暴力访问
        constructor.setAccessible(true);

        // 创建对象
        Cat cat = (Cat) constructor.newInstance("三花");
        System.out.println(cat.getName());  // 输出: 三花
    }
}

反射操作成员变量

获取成员变量

import java.lang.reflect.Field;

// 获取所有 public 字段
Field[] fields = clazz.getFields();

// 获取所有字段(包括 private)
Field[] declaredFields = clazz.getDeclaredFields();

// 获取指定字段
Field nameField = clazz.getDeclaredField("name");

赋值和取值

// 假设有一个 Cat 类,有 private String name 字段
Cat cat = new Cat();

// 获取字段
Field nameField = clazz.getDeclaredField("name");

// 暴力访问(private 字段需要)
nameField.setAccessible(true);

// 赋值
nameField.set(cat, "小白");  // cat.name = "小白"

// 取值
String name = (String) nameField.get(cat);  // 读取 cat.name

完整示例

public class FieldDemo {
    public static void main(String[] args) throws Exception {
        Class<?> clazz = Cat.class;
        Cat cat = (Cat) clazz.getDeclaredConstructor().newInstance();

        // 获取所有字段并输出
        for (Field field : clazz.getDeclaredFields()) {
            System.out.println("字段名: " + field.getName() +
                             ", 类型: " + field.getType());
        }

        // 操作 name 字段
        Field nameField = clazz.getDeclaredField("name");
        nameField.setAccessible(true);
        nameField.set(cat, "小白");

        System.out.println("name = " + nameField.get(cat));
    }
}

反射操作成员方法

获取成员方法

import java.lang.reflect.Method;

// 获取所有 public 方法(不包括继承的 Object 方法)
Method[] methods = clazz.getMethods();

// 获取所有方法(包括 private)
Method[] declaredMethods = clazz.getDeclaredMethods();

// 获取指定方法(方法名 + 参数类型)
Method eatMethod = clazz.getDeclaredMethod("eat");
Method playMethod = clazz.getDeclaredMethod("play", String.class);  // play(String)

执行方法

Cat cat = new Cat();

// 获取方法
Method eatMethod = clazz.getDeclaredMethod("eat");

// 暴力访问
eatMethod.setAccessible(true);

// 执行方法(invoke:激活/调用)
// 无参数方法
eatMethod.invoke(cat);

// 有参数方法
Method playMethod = clazz.getDeclaredMethod("play", String.class);
playMethod.invoke(cat, "毛球");  // cat.play("毛球")

完整示例

public class MethodDemo {
    public static void main(String[] args) throws Exception {
        Class<?> clazz = Cat.class;
        Cat cat = (Cat) clazz.getDeclaredConstructor().newInstance();

        // 执行 eat 方法
        Method eatMethod = clazz.getDeclaredMethod("eat");
        eatMethod.setAccessible(true);
        eatMethod.invoke(cat);

        // 执行 play 方法
        Method playMethod = clazz.getDeclaredMethod("play", String.class);
        playMethod.setAccessible(true);
        playMethod.invoke(cat, "毛球");
    }
}

反射的应用场景

场景说明
Spring 依赖注入通过反射读取 @Autowired 注解,自动注入 Bean
MyBatis读取映射文件,自动将 ResultSet 映射到对象
AOP动态代理,在方法前后增强逻辑(如 字段填充.md 中的 AutoFill)
Jackson 反序列化将 JSON 字符串转换为 Java 对象
Spring MVC根据请求路径自动调用对应的 Controller 方法
工厂模式配置文件 + 反射实现松耦合的对象创建

反射的优缺点

优点

  • 动态性:在运行时决定操作哪个类,提高灵活性
  • 解耦:配合配置文件,实现松耦合设计

缺点

  • 性能开销:反射涉及类型检查和权限检查,比直接调用慢
  • 安全问题:可以访问 private 成员,破坏封装性
  • 复杂度高:代码可读性差,调试困难

常用 API 速查表

分类方法说明
Class 获取Class.forName("类名")通过全限定名获取
类名.class通过 class 属性获取
对象.getClass()通过对象获取
构造器getDeclaredConstructors()获取所有构造器
getDeclaredConstructor(参数类型...)获取指定构造器
newInstance(参数...)创建对象
字段getDeclaredFields()获取所有字段
getDeclaredField("字段名")获取指定字段
set(对象, 值) / get(对象)赋值/取值
方法getDeclaredMethods()获取所有方法
getDeclaredMethod("方法名", 参数类型...)获取指定方法
invoke(对象, 参数...)执行方法