ReflectionUtils反射工具:精要介绍与实战应用指南

本文详细介绍了Spring框架中的ReflectionUtils工具类,涵盖获取Class对象、访问和修改私有字段、调用私有方法、构造实例以及注意事项等内容,展示了如何通过反射进行常见的编程操作。
摘要由CSDN通过智能技术生成
❃博主首页 : 「码到三十五」 ,同名公众号 :「码到三十五」,wx号 : 「liwu0213」
☠博主专栏 : <mysql高手> <elasticsearch高手> <源码解读> <java核心> <面试攻关>
♝博主的话 : 搬的每块砖,皆为峰峦之基;公众号搜索「码到三十五」关注这个爱发技术干货的coder,一起筑基

一、ReflectionUtils工具类介绍

org.springframework.util.ReflectionUtils 是 Spring 框架提供的一个反射工具类,它封装了 Java 反射 API 的一些常用操作,使得我们能够更加方便、简洁地使用反射功能。。

1. 获取 Class 对象

ReflectionUtils 提供了多种获取 Class 对象的方法,如:

  • findClass(String name): 根据类名获取 Class 对象,与 Class.forName(String) 类似,但会缓存已经加载过的类。
  • getClass(Object obj): 获取对象的运行时类,与 obj.getClass() 等效。
  • getUserClass(Object obj): 如果对象是代理对象,则获取其背后的实际类(即目标类),否则与 getClass(Object) 相同。

2. 访问字段(Field)

这个工具类也简化了对字段的访问操作:

  • findField(Class<?> clazz, String name): 在给定的类及其父类中查找具有指定名称的字段。
  • findField(Class<?> clazz, String name, Class<?> type): 根据名称和类型查找字段。
  • getField(Field field): 获取可访问的字段对象,如果字段是私有的,会设置其为可访问。
  • setField(Object obj, String name, Object value): 设置指定对象的字段值。
  • getFieldValue(Object obj, String name): 获取指定对象的字段值。

3. 调用方法(Method)

ReflectionUtils 同样提供了方法来简化方法的调用:

  • findMethod(Class<?> clazz, String name, Class<?>... paramTypes): 查找具有指定名称和参数类型的方法。
  • invokeMethod(Method method, Object target): 调用无参数方法。
  • invokeMethod(Method method, Object target, Object... args): 调用带参数的方法。
  • invokeJdbcMethod(Method method, Object target, Object... args): 专为 JDBC 方法设计的调用,处理 SQL 异常。
  • makeAccessible(Method method): 确保方法可以访问,即使它是私有的。

4. 构造函数和实例化

这个工具类还提供了通过构造函数创建类实例的方法:

  • getConstructorIfAvailable(Class<?> clazz, Class<?>... paramTypes): 尝试获取指定参数类型的构造函数,如果找不到则返回 null
  • instantiateClass(Constructor<?> ctor, Object... args): 使用指定的构造函数和参数实例化类。
  • newInstance(Class<?> clazz, Object... args): 简化版的实例化方法,它内部会查找合适的构造函数并调用 instantiateClass

5. 其他实用方法

  • isAssignable(Class<?> lhsType, Class<?> rhsType): 判断一个类是否可以赋值给另一个类(考虑继承关系)。
  • doesMethodDeclareException(Method method, Class<?> exceptionType): 检查方法是否声明了指定类型的异常。
  • getUniqueDeclaredMethods(Class<?> leafClass): 获取类中声明的所有方法,包括继承的方法,但排除重写的方法,确保每个方法只出现一次。
  • getAllDeclaredMethods(Class<?> leafClass): 获取类中声明的所有方法,包括继承的方法,但不排除重写的方法。
  • getDeclaredMethods(Class<?> clazz): 获取类中直接声明的所有方法,不包括继承的方法。
  • getDeclaredFields(Class<?> clazz): 获取类中直接声明的所有字段。

注意事项

虽然 ReflectionUtils 提供了很多便捷的方法,但使用反射仍然需要谨慎。反射操作可能会破坏封装性、增加性能开销,并可能引发安全问题。因此,在不需要动态访问的情况下,最好避免使用反射。

二、ReflectionUtils源码解读

以下是 ReflectionUtils 类中部分方法的代码:

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

import org.springframework.lang.Nullable;

public abstract class ReflectionUtils {

    // 缓存已解析的类
    private static final Class<?>[] EMPTY_CLASS_ARRAY = {};

    // ... 其他常量和方法 ...

    // 获取类的方法,处理了类加载异常
    @Nullable
    public static Class<?> findClass(String name) throws ClassNotFoundException {
        // 省略了缓存逻辑和类加载器的详细处理
        return Class.forName(name, false, getDefaultClassLoader());
    }

    // 判断方法是否声明了某个异常
    public static boolean doesMethodDeclareException(Method method, Class<?> exceptionType) {
        Class<?>[] declaredExceptions = method.getExceptionTypes();
        for (Class<?> declaredException : declaredExceptions) {
            if (declaredException.isAssignableFrom(exceptionType)) {
                return true;
            }
        }
        return false;
    }

    // 使字段可访问,并返回字段对象
    public static Field getField(Field field) {
        makeAccessible(field);
        return field;
    }

    // 设置字段的值
    public static void setField(Object obj, String fieldName, @Nullable Object value) {
        Field field = findField(obj.getClass(), fieldName);
        if (field == null) {
            throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + obj + "]");
        }
        makeAccessible(field);
        try {
            field.set(obj, value);
        } catch (IllegalAccessException ex) {
            throw new IllegalStateException("Cannot access field [" + fieldName + "] on target [" + obj + "]", ex);
        }
    }

    // 获取字段的值
    @Nullable
    public static Object getFieldValue(Object obj, String fieldName) {
        Field field = findField(obj.getClass(), fieldName);
        if (field == null) {
            throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + obj + "]");
        }
        makeAccessible(field);
        try {
            return field.get(obj);
        } catch (IllegalAccessException ex) {
            throw new IllegalStateException("Cannot access field [" + fieldName + "] on target [" + obj + "]", ex);
        }
    }

    // 查找类中的字段
    @Nullable
    public static Field findField(Class<?> clazz, String name) {
        return findField(clazz, name, null);
    }

    // 查找类中的字段,考虑字段类型
    @Nullable
    public static Field findField(Class<?> clazz, String name, @Nullable Class<?> type) {
        Class<?> searchType = clazz;
        while (searchType != null && searchType != Object.class) {
            Field[] fields = searchType.getDeclaredFields();
            for (Field field : fields) {
                if ((name == null || name.equals(field.getName())) && (type == null || type.equals(field.getType()))) {
                    return field;
                }
            }
            searchType = searchType.getSuperclass();
        }
        return null;
    }

    // ... 省略了其他方法 ...

    // 设置可访问性的通用方法
    public static void makeAccessible(AccessibleObject accessibleObject) {
        if ((!Modifier.isPublic(accessibleObject.getModifiers()) ||
                !Modifier.isPublic(accessibleObject.getDeclaringClass().getModifiers())) &&
                !accessibleObject.isAccessible()) {
            accessibleObject.setAccessible(true);
        }
    }

    // ... 省略了其他方法 ...
}

以上代码只是一个丐版,并不是 ReflectionUtils 类的完整实现。

三、ReflectionUtils的使用

获取类的私有字段值

有一个类 Person,它有一个私有字段 name,想要通过反射来获取这个私有字段的值。

import org.springframework.util.ReflectionUtils;

public class Person {
    private String name;

    public Person(String name) {
        this.name = name;
    }

    // 省略其他方法...
}

public class ReflectionExample {
    public static void main(String[] args) {
        Person person = new Person("John Doe");
        String fieldName = "name";

        // 使用 ReflectionUtils 获取私有字段的值
        String nameValue = (String) ReflectionUtils.getFieldValue(person, fieldName);
        System.out.println("Name value: " + nameValue); // 输出: Name value: John Doe
    }
}

设置类的私有字段值

想要通过反射来设置私有字段 name 的值,可以这样:

public class ReflectionExample {
    public static void main(String[] args) {
        Person person = new Person("John Doe");
        String fieldName = "name";
        String newValue = "Jane Doe";

        // 使用 ReflectionUtils 设置私有字段的值
        ReflectionUtils.setField(person, fieldName, newValue);

        // 再次获取并验证字段值已更改
        String updatedValue = (String) ReflectionUtils.getFieldValue(person, fieldName);
        System.out.println("Updated name value: " + updatedValue); // 输出: Updated name value: Jane Doe
    }
}

调用私有方法

假设 Person 类有一个私有方法 sayHello(),想要通过反射来调用这个方法。

import org.springframework.util.ReflectionUtils;

public class Person {
    // ... 省略其他字段和方法 ...

    private void sayHello() {
        System.out.println("Hello, I'm a private method!");
    }
}

public class ReflectionExample {
    public static void main(String[] args) {
        Person person = new Person("John Doe");
        String methodName = "sayHello";

        // 使用 ReflectionUtils 调用私有方法(无参数)
        ReflectionUtils.invokeMethod(ReflectionUtils.findMethod(Person.class, methodName), person);
        // 输出: Hello, I'm a private method!
    }
}

检查方法是否声明了特定异常

想要检查一个方法是否声明了抛出某个特定类型的异常,可以使用 doesMethodDeclareException 方法。

import org.springframework.util.ReflectionUtils;
import java.io.IOException;

public class ExampleWithException {
    public void methodThatThrows() throws IOException {
        // ... 方法实现 ...
    }
}

public class ReflectionExample {
    public static void main(String[] args) {
        boolean declaresException = ReflectionUtils.doesMethodDeclareException(
                ReflectionUtils.findMethod(ExampleWithException.class, "methodThatThrows"), IOException.class);
        System.out.println("Declares IOException: " + declaresException); // 输出: Declares IOException: true
    }
}

使用 ReflectionUtils 类来处理常见的反射任务,如获取和设置私有字段的值,以及调用私有方法和检查方法异常声明。


关注公众号获取更多技术干货 !

  • 26
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
《dama-dmbok2.0数据管理知识体系指南核心精要》是数据管理领域的权威指南,为从业人员提供了全面的数据管理知识,并帮助他们在实践中达到最佳结果。该指南对数据管理的核心概念和要素进行了系统的梳理和总结。 该指南包含了十个数据管理主题,涵盖了数据管理的方方面面。这些主题包括数据战略规划、数据架构与设计、数据建模与设计、数据质量管理、数据存储与操作、数据安全与隐私保护、数据集成与交换、数据生命周期管理、数据治理与合规性、数据组织与管理。 在数据战略规划主题中,指南介绍了如何制定与组织的数据管理战略、策略和计划。数据架构与设计主题涉及了如何构建一个既满足业务需求,又具有可扩展性和可持续发展性的数据架构。数据建模与设计主题涵盖了数据模型的设计原则和最佳实践。 数据质量管理主题探讨了确保数据质量的方法和技术,包括数据清洗、数据验证和数据修复。数据存储与操作主题讲解了各种数据存储和操作技术,如数据库管理系统和数据仓库。 数据安全与隐私保护主题强调了数据安全和隐私保护的重要性,介绍了相关的法律法规和最佳实践。数据集成与交换主题涉及了如何整合和共享不同来源和格式的数据。 数据生命周期管理主题讨论了从数据收集到数据销毁的整个数据生命周期的管理。数据治理与合规性主题介绍了如何建立有效的数据治理框架和确保合规性。 最后,数据组织与管理主题强调了数据管理团队的构建和组织,以及数据管理的日常运营和管理。 总之,dama-dmbok2.0数据管理知识体系指南核心精要是一本全面而实用的指南,提供了数据管理各个方面的核心概念和要素,帮助数据管理从业人员在实践中取得成功。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码到三十五

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值