Java反射

Mathieu 于 2025-07-27 发布

反射

概念

个人理解反射就是Java能在仅知道类的路径(java.lang.Runtime)和类名的情况下动态的调用里面的方法

代码示例

假设目标存在一个User方法,代码如下:

public class User {
    private String name;
    private int age;

    public User() {
        System.out.println("调用无参构造函数");
    }

    public User(String name, int age) {
        this.name = name;
        this.age = age;
        System.out.println("调用有参构造函数");
    }

    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;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

使用反射代码示例:

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

public class ReflectionExample {
    public static void main(String[] args) throws Exception {

        // 获取 Class 对象的几种方式
        // 方式1: 通过类名.class
        Class<User> userClass1 = User.class;

        // 方式2: 通过实例对象的 getClass() 方法
        User user = new User();
        Class userClass2 = user.getClass();

        // 方式3: 通过 Class.forName() 方法(最常用,可以动态加载类)
        Class<?> userClass3 = Class.forName("User"); // 包名+类名

        System.out.println("--- 1. 创建对象:通过反射调用构造函数 ---");

        // 获取无参构造函数并创建对象
        Constructor<User> constructor = userClass1.getDeclaredConstructor();
        User user1 = constructor.newInstance(); // 相当于 new User()
        System.out.println("创建的对象1: " + user1);

        // 获取有参构造函数并创建对象
        Constructor<User> constructorWithParams = userClass1.getDeclaredConstructor(String.class, int.class);
        User user2 = constructorWithParams.newInstance("张三", 25); // 相当于 new User("张三", 25)
        System.out.println("创建的对象2: " + user2);

        System.out.println("\n--- 2. 调用方法:通过反射调用方法 ---");

        // 获取 setName 方法
        Method setNameMethod = userClass1.getDeclaredMethod("setName", String.class);
        // 调用 setName 方法,参数为 (对象实例, 方法参数)
        setNameMethod.invoke(user1, "李四");
        System.out.println("调用setName方法后的对象: " + user1);

        // 获取 getName 方法
        Method getNameMethod = userClass1.getDeclaredMethod("getName");
        // 调用 getName 方法
        String name = (String) getNameMethod.invoke(user1);
        System.out.println("调用getName方法获取到的值: " + name);

        System.out.println("\n--- 3. 访问成员变量:通过反射获取和修改私有成员变量 ---");

        // 获取 name 成员变量,包括私有变量
        Field nameField = userClass1.getDeclaredField("name");
        // 如果成员变量是私有的,需要设置为可访问
        nameField.setAccessible(true);

        // 获取 name 的值
        String fieldName = (String) nameField.get(user2);
        System.out.println("获取到的name字段值: " + fieldName);

        // 修改 name 的值
        nameField.set(user2, "王五");
        System.out.println("修改name字段后的对象: " + user2);
    }
}

假设只知道User类名,其他的啥都不知道,要先调出存在的方法再去执行其中一个,代码如下:

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Arrays;

public class DynamicMethodCaller {
    public static void main(String[] args) throws Exception {

        // 假设我们只知道类名是 "User"
        String className = "User";
        // 假设我们要调用的方法是 "setName"
        String targetMethodName = "setName";
        // 假设要传入的参数值是 "张三"
        Object[] arguments = {"张三"};

        // 1. 获取 Class 对象
        Class<?> clazz = Class.forName(className);

        // 2. 动态获取并分析方法
        Method targetMethod = null;
        System.out.println("正在寻找方法: " + targetMethodName);

        // 获取所有公共方法
        Method[] methods = clazz.getMethods();
        for (Method method : methods) {
            // 找到名字匹配的方法
            if (method.getName().equals(targetMethodName)) {
                targetMethod = method;
                System.out.println("  - 找到目标方法: " + method.getName());

                // 获取参数数量
                int paramCount = method.getParameterCount();
                System.out.println("  - 参数数量: " + paramCount);

                // 获取并打印参数类型
                if (paramCount > 0) {
                    Class<?>[] paramTypes = method.getParameterTypes();
                    System.out.println("  - 参数类型: " + Arrays.toString(paramTypes));
                }

                break; // 找到后立即退出循环
            }
        }

        // 3. 动态调用方法
        if (targetMethod != null) {
            // 获取无参构造函数来创建实例
            Object instance = clazz.getDeclaredConstructor().newInstance();

            // 检查传入的参数数量是否与方法需要的参数数量匹配
            if (targetMethod.getParameterCount() != arguments.length) {
                System.err.println("错误: 传入的参数数量不匹配!");
                return;
            }

            System.out.println("\n正在调用方法...");
            // 调用 invoke 方法,传入实例和参数
            targetMethod.invoke(instance, arguments);

            // 验证结果
            Method getNameMethod = clazz.getMethod("getName");
            Object result = getNameMethod.invoke(instance);
            System.out.println("调用成功!结果为: " + result);

        } else {
            System.err.println("错误: 找不到方法 " + targetMethodName + "!");
        }
    }
}

反射调用执行命令

Runtime.getRuntime().exec(String command)

import java.lang.reflect.Method;

public class SimplifiedReflectiveCalcExec1 {
    public static void main(String[] args) throws Exception {
        // 获取 Runtime 类的 Class 对象
        Class<?> runtimeClass = Class.forName("java.lang.Runtime");

        // 获取 getRuntime() 静态方法并调用,获取 Runtime 实例
        Method getRuntimeMethod = runtimeClass.getMethod("getRuntime");
        Object runtimeInstance = getRuntimeMethod.invoke(null);

        // 获取 exec(String) 方法并调用,执行命令
        Method execMethod = runtimeClass.getMethod("exec", String.class);
        execMethod.invoke(runtimeInstance, "calc.exe");
    }
}

思维导图:

Java反射调用exec.png

反射调用 ProcessBuilder (间接方式)

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

public class SimplifiedReflectiveProcessBuilderCalc {
    public static void main(String[] args) throws Exception {
        // 获取 ProcessBuilder 类的 Class 对象
        Class<?> processBuilderClass = Class.forName("java.lang.ProcessBuilder");

        // 获取 ProcessBuilder 的 String... command 构造函数
        Constructor<?> constructor = processBuilderClass.getConstructor(String[].class);

        // 准备命令参数
        String[] command = {"calc.exe"};

        // 通过反射实例化 ProcessBuilder
        Object processBuilderInstance = constructor.newInstance(new Object[]{command});

        // 获取 start() 方法并调用,执行命令
        Method startMethod = processBuilderClass.getMethod("start");
        startMethod.invoke(processBuilderInstance);
    }
}