【Hutool系列】反射工具-ReflectUtil
前言
反射是 Java 中一种强大的机制,可以在运行时动态地获取类的信息并操作类的属性和方法。在 Java 中,通过反射可以获取和设置类的字段、调用类的方法、创建类的实例等。Java的反射机制,可以让语言变得更加灵活,对对象的操作也更加“动态”,因此在某些情况下,反射可以做到事半功倍的效果。本文将介绍如何使用Hutool中的反射工具类来获取获取类信息、操作字段、调用方法、构造对象等常见功能,并提供了相关的代码示例。
一、概述
1.1 工具简介
Hutool是一个Java工具类库,提供了很多常用的工具类和方法,包括反射操作。通过Hutool,我们可以更加方便地使用反射来获取类的属性值。Hutool针对Java的反射机制做了工具化封装,封装包括获取构造方法、获取字段、获取字段值、获取方法、执行方法(对象方法和静态方法)等。示例如下所示:
// 获取某个类的所有方法
Method[] methods = ReflectUtil.getMethods(PmsBrand.class);
// 获取某个类的指定方法
Method method = ReflectUtil.getMethod(PmsBrand.class, "getId");
// 使用反射来创建对象
PmsBrand pmsBrand = ReflectUtil.newInstance(PmsBrand.class);
// 反射执行对象的方法
ReflectUtil.invoke(pmsBrand,"setId",1);
return CommonResult.success(null,"操作成功!");
1.2 引入依赖
在使用Hutool工具之前,我们需要将Hutool添加到项目的依赖中。如果使用Maven构建项目,可以在 pom.xml 文件中添加以下依赖:
<!-- https://mvnrepository.com/artifact/cn.hutool/hutool-all -->
<dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>${hutool.version}</version>
</dependency>
Hutool-all 是一个 Hutool 的集成打包产品,由于考虑到“懒人”用户及分不清各个模块作用的用户,“无脑”引入 hutool-all 模块是快速开始和深入应用的最佳方式。如果你想像 SpringBoot 一样引入 Hutool,再由子模块决定用到哪些模块,你可以在父模块中加入:
<dependencyManagement><dependencies><dependency><groupId>cn.hutool</groupId><artifactId>hutool-bom</artifactId><version>${hutool.version}</version><type>pom</type><!-- 注意这里是import --><scope>import</scope></dependency></dependencies>
</dependencyManagement>
然后再在子模块中就可以引入自己需要的模块了:
<dependencies><dependency><groupId>cn.hutool</groupId><artifactId>hutool-core</artifactId></dependency>
</dependencies>
二、基本使用示例
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {private String name;private Integer age;private Boolean gender;
}
2.1 工具类的基本结构
工具类通常由静态方法组成,并且构造函数设为私有以防止实例化,如下所示。
public class ReflectUtil {// 私有构造函数,防止实例化public ReflectUtil() {}
}
2.2 对类的操作
ReflectionUtil 是一个Java反射工具类,它提供了一些简化反射操作的方法。ReflectionUtil 可以获取类的各种信息,比如类名、类的修饰符、类的父类、实现的接口等,这些信息可以通过调用 ReflectionUtil 的方法来获取。
构造对象
通过反射创建对象,包括使用无参和有参构造方法,如下所示。
@Test
public void constructorTest() {// 获取所有构造方法Constructor<User>[] constructors = ReflectUtil.getConstructors(User.class);for (Constructor<User> constructor : constructors) {Console.log("getConstructors->获取构造方法:", constructor);}// 获取无参构造方法Constructor<User> constructor = ReflectUtil.getConstructor(User.class);Console.log("getConstructor->获取无参构造方法:", constructor);// 获取有参构造方法Constructor<User> constructor1 = ReflectUtil.getConstructor(User.class, String.class, Integer.class,Boolean.class);Console.log("getConstructor->获取有参构造方法:", constructor1);String name = constructor1.getName();Console.log("name:{}", name);int modifiers = constructor1.getModifiers();Console.log("modifiers:{}", modifiers);}
创建类实例
ReflectionUtil 可以通过反射来创建对象,它提供了一个newInstance 方法,可以根据类名来创建相应的对象。
@Test
public void newInstanceTest() {ReflectUtil.newInstance(User.class);
}
2.3 对方法的操作
通过反射调用类的方法,包括获取方法和执行方法,ReflectionUtil 同样提供了方法来简化方法的调用,一些儿常用方法如下所示。
// 查找指定方法。如果找不到对应的方法则返回null
Method getMethod(Class<?> clazz, boolean ignoreCase, String methodName, Class<?>... paramTypes);// 按照方法名查找指定方法名的方法,只返回匹配到的第一个方法,如果找不到对应的方法则返回null
Method getMethodIgnoreCase(Class<?> clazz, String methodName, Class<?>... paramTypes);// 查找指定方法。如果找不到对应的方法则返回null
Method getMethodByName(Class<?> clazz, boolean ignoreCase, String methodName);// 获得指定类中的方法名
Method[] getMethods(Class<?> beanClass);// 调用方法。
T invoke(Object obj, Method method, Object... args) throws InvocationTargetRuntimeException, UtilException;// 执行方法
T invoke(Object obj, String methodName, Object... args) throws UtilException;
T invokeRaw(Object obj, Method method, Object... args) throws InvocationTargetException, IllegalAccessException;// 执行静态方法
T invokeStatic(Method method, Object... args) throws UtilException;// 执行方法,执行前要检查给定参数
T invokeWithCheck(Object obj, Method method, Object... args) throws UtilException;
获取类的方法
/*** 获取某个类的所有方法*/
@Test
public void getMethodsTest() {Method[] methods = ReflectUtil.getMethods(User.class);Arrays.stream(methods).forEach(System.out::println);
}/*** 获取某个类的指定方法*/
@Test
public void getMethodTest() {Method methods = ReflectUtil.getMethod(User.class, "getName");
}
调用方法
ReflectionUtil 可以通过反射来调用类的方法,它提供了 invokeXXXX
方法,可以根据方法名和参数类型来调用相应的方法。
@Test
public void invokeMethodTest() {ReflectUtil.invoke(User.class, "setName", "独泪了无痕");
}
2.4 对属性的操作
ReflectUtil 也简化了对字段的访问操作,可以通过反射来获取对象的字段值,它提供了一个 getFieldValue
方法,可以根据字段名来获取相应的字段值。除此之外,还可以通过反射来设置对象的字段值,提供了一个 setFieldValue
方法,可以根据字段名来设置相应的字段值。
// 查找指定类中的指定name的字段,也包括父类和Object类的字段,字段不存在则返回null
Field getField(Class<?> beanClass, String name);// 获取指定类中字段名和字段对应的有序Map,包括其父类中的字段。
// 如果子类与父类中存在同名字段,则这两个字段同时存在,子类字段在前,父类字段在后
Map<String, Field> getFieldMap(Class<?> beanClass);// 获取字段名,如果存在Alias注解,读取注解的值作为名称
String getFieldName(Field field);// 获得一个类中所有字段列表,包括其父类中的字段。
// 如果子类与父类中存在同名字段,则这两个字段同时存在,子类字段在前,父类字段在后
Field[] getFields(Class<?> beanClass);// 获取指定对象所有字段的值
Object[] getFieldsValue(Object obj);// 获取字段值
Object getFieldValue(Object obj, Field field);
Object getFieldValue(Object obj, String fieldName);
获取类的属性字段
@Test
public void getFieldsTest() {User user = new User();// 获取实体中所有属性字段Field[] fields = ReflectUtil.getFields(user.getClass());Arrays.stream(fields).forEach(field -> {Console.log("getFields-获取User类的所有字段:", field);Console.log("getFieldName->获取字段名:", ReflectUtil.getFieldName(field));Console.log("getFieldValue->获取字段值:", ReflectUtil.getFieldValue(new User(), field));Console.log("getModifiers->获取字段修饰符:", field.getModifiers());Console.log("getType->获取字段类型:", field.getType());Console.log("获取属性字段类型:", field.getType().getCanonicalName());});
}
获取类的字段值
通过 Hutool 中的 ReflectUtil 类,我们可以获取Java类的字段值,如下所示:
@Test
public void getFieldValueTest() {User user = new User();user.setName("独泪了无痕");user.setAge(30);user.setGender(true);System.out.println("Name:" + ReflectUtil.getFieldValue(user, "name"));System.out.println("Age:" + ReflectUtil.getFieldValue(user, "age"));System.out.println("Gender:" + ReflectUtil.getFieldValue(user, "gender"));
}
在上面的示例中,我们通过 ReflectUtil.getFieldValue()
方法获取了类的字段值。该方法接受两个参数,第一个参数是要获取字段值的对象,第二个参数是字段的名称。
三、总结
ReflectUtils类通过结合Java反射和Lambda表达式,提供了一种简洁高效的方式来操作对象的字段。它不仅提高了代码的可读性,还通过缓存机制优化了性能。掌握这个工具类的使用,将有助于提升Java开发的灵活性和效率。但使用反射仍然需要谨慎。反射操作可能会破坏封装性、增加性能开销,并可能引发安全问题。因此,在不需要动态访问的情况下,最好避免使用反射。
Hotool 不仅仅只有这一种工具类,还包含了其他许多工具类。在这里我作为一名Hutool的用户,我感谢Hutool的创作者和维护者们为我们带来如此强大便捷的工具库,希望Hutool功能越来越完善,为我们的开发工作带来更多的便利。同时也祝愿所有开发者没有BUG困扰,能够愉快地编写出高效、功能完善的程序。
相关文章:

【Hutool系列】反射工具-ReflectUtil
前言 反射是 Java 中一种强大的机制,可以在运行时动态地获取类的信息并操作类的属性和方法。在 Java 中,通过反射可以获取和设置类的字段、调用类的方法、创建类的实例等。Java的反射机制,可以让语言变得更加灵活,对对象的操作也更…...
【操作系统专业课】第二次作业
第1题(进程同步与互斥) 使用二值信号量实现 n 个进程之间的互斥。 1. 定义一个二值信号量 mutex= 1。 二值信号量:二值信号量只有两种取值,0 (资源已被占用)和 1(资源可用)。 2. 进程进入临界区前的操作:每个进程在进入临界区之前,都需要执行 P(mutex) 操作。 P 操作…...
Scala的迭代器
1.对比foreach 它的优点在于: (1) 内存效率高。迭代器采用延迟计算的方式,它不会将整个集合加载到内存中,而是在每次调用next方法时才计算并返回下一个元素。 (2) 统一的遍历方法。迭代器为不同类型的集合(如列表、集合、映射等…...

(RK3566驱动开发 - 1).pinctrl和gpio子系统
一.设备树 pinctrl部分可以参考 rockchip 官方的绑定文档 :kernel/Documentation/devicetree/bindings/pinctrl PIN_BANK:引脚所属的组 - 本次例程使用的是 GPIO3_A1 这个引脚,所以所属的组为 3; PIN_BANK_IDX:引脚的…...

css三角制作(二十课)
代码: <style>/* 边框原理 */.box1 {width: 0;height: 0;border-top: 100px solid pink;border-bottom: 100px solid blue;border-left: 100px solid yellow;border-right: 100px solid greenyellow;}/* 三角制作 */.box2 {width: 0;height: 0;border: 100px …...

C++_priority_queue(优先级队列)
✨✨ 欢迎大家来到小伞的大讲堂✨✨ 🎈🎈养成好习惯,先赞后看哦~🎈🎈 所属专栏:C学习 小伞的主页:xiaosan_blog 1. priority_queue的介绍和使用 priority_queue文档介绍 优先级队列的实现的关键…...

微信小程序——01开发前的准备和开发工具
文章目录 一、开发前的准备1注册小程序账号2安装开发者工具 二、开发者工具的使用1创建项目2 工具的使用3目录结构4各个页面之间的关系5 权限管理6提交审核和发布 一、开发前的准备 开发前需要进行以下准备: 1 注册小程序账号2激活邮箱3 信息登记4 登录小程序管理后…...
MySQL 的主从复制数据同步
一、什么是 MySQL 的主从复制 MySQL 的主从复制(Master-Slave Replication)是一种将数据从一个主数据库服务器(主库)复制到一个或多个从数据库服务器(从库)的技术。主库负责所有的数据写操作,从…...

python——面向对象
一、面向对象编程 1.1 面向过程与面向对象 面向过程和面向对象都是一种编程方式,只不过再设计上有区别。 1.1.1 面向过程pop: 举例:孩子上学 1. 妈妈起床 2. 妈妈洗漱 3. 妈妈做饭 4. 妈妈把孩子叫起来 5. 孩子起床 6. 孩子洗漱 7. 孩子吃…...

Microsoft 365 Exchange如何设置可信发件IP白名单
1、 进入到 Microsoft 365 admin center 管理中心 ,点击 管理中心 下的 安全 在弹出的新页面中,依次点击 策略和规则 – 威胁策略 – 反垃圾邮件 再单击 连接筛选器策略(默认) – 编辑连接筛选器策略 2、在 IP 允许列表 中添加可信邮件 IP 段࿰…...

LM27313典型电路之升压电路
下图为升压芯片LM27313典型电路图: 从图中可以看出:系统电压VSYS3.7伏,通过C26与C27两个滤波电容后,到达升压芯片的VIN输入脚pin5。 其中电源芯片的电压输出由下式子决定: VOUT1.23*(1R17/R21) 其中VOUT是图中的V5D…...

嵌入式面试八股文(七)·#ifndef#define#endif的作用、以及内存分区(全局区、堆区、栈区、代码区)
目录 1. 头文件中的#ifndef / #define / #endif的作用是什么? 2. 内存分区:全局区、堆区、栈区、代码区简单描述? 2.1 代码区(Text Segment): 2.2 全局区(Data Segment)&…...

【弱监督视频异常检测】2024-ESWA-基于扩散的弱监督视频异常检测常态预训练
2024-ESWA-Diffusion-based normality pre-training for weakly supervised video anomaly detection 基于扩散的弱监督视频异常检测常态预训练摘要1. 引言2. 相关工作3. 方法论3.1. 使用扩散自动编码器进行常态学习3.2. 全局-局部特征编码器3.2.1 局部块3.2.2 全局块3.2.3 协同…...
Android 13 实现屏幕熄屏一段时候后关闭 Wi-Fi 和清空多任务列表
明白了,您这个补丁的功能是当设备屏幕关闭一段时间后,自动关闭 Wi-Fi 连接并清空多任务菜单。以下是更新后的博客内容,包含了对功能的详细解释和代码实现: 修改 PowerManagerService.java 以实现屏幕灭屏后关闭 Wi-Fi 和清空多任务菜单功能 在本篇博客中,我们将介绍一个针…...
Elasticsearch磁盘占用大于95%时将所有索引置为只读
在一个稳定运行的功能中,突然收到报错。经查明,是在向 Elasticsearch 中插入文档时出现了错误: AuthorizationException: AuthorizationException(403, ucluster_block_exception, ublocked by: [FORBIDDEN/12/index read-only / allow delete (api)];) 网上也有其他人报出类…...
删除 git config 保存的密码
要从 Git 中删除保存的密码,你可以根据你之前使用的保存方法来操作。以下是一些常见的方法来删除 Git 中保存的密码: 删除 credential.helper 中的密码 如果你之前使用 store 或 cache 作为 credential.helper,你可以执行以下步骤来删除保存…...
Springboot环境搭建详解
springboot学习视频记录: 笔记: a:Springboot maven常见依赖、配置文件笔记-CSDN博客 b:Springboot环境搭建详解-CSDN博客 day01 6:springboot的parent和starter依赖- a 7:启动类的位置配置- b 8&am…...

SpringCloud框架学习(第三部分:Resilience4j 与 Micrometer)
目录 九、CircuitBreaker断路器 1.前言(Hystrix) 2.服务雪崩 3.Circuit Breaker 4. Resilience4j 5.案例实战 (1)熔断(服务熔断 服务降级) Ⅰ. 按照 COUNT_BASED(计数的滑动窗口…...
Scala的Map集合(不可变)
package gxy//类型:不可变,可变 //操作:添加元素,删除元素,查询元素,移除元素,遍历 object map {def main(args: Array[String]): Unit {//不可变mapval map1 Map("鄂" -> "…...
深入剖析:Spring MVC与Struts的较量
标题:深入剖析:Spring MVC与Struts的较量 引言 在Java Web开发领域,Spring MVC和Struts是两个非常流行的框架。它们各自拥有不同的特点,适用于不同的应用场景。本文将深入探讨Spring MVC和Struts的区别,从底层机制、…...
conda相比python好处
Conda 作为 Python 的环境和包管理工具,相比原生 Python 生态(如 pip 虚拟环境)有许多独特优势,尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处: 一、一站式环境管理:…...

LeetCode - 394. 字符串解码
题目 394. 字符串解码 - 力扣(LeetCode) 思路 使用两个栈:一个存储重复次数,一个存储字符串 遍历输入字符串: 数字处理:遇到数字时,累积计算重复次数左括号处理:保存当前状态&a…...

深入理解JavaScript设计模式之单例模式
目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式(Singleton Pattern&#…...

Python爬虫(一):爬虫伪装
一、网站防爬机制概述 在当今互联网环境中,具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类: 身份验证机制:直接将未经授权的爬虫阻挡在外反爬技术体系:通过各种技术手段增加爬虫获取数据的难度…...

使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台
🎯 使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台 📌 项目背景 随着大语言模型(LLM)的广泛应用,开发者常面临多个挑战: 各大模型(OpenAI、Claude、Gemini、Ollama)接口风格不统一;缺乏一个统一平台进行模型调用与测试;本地模型 Ollama 的集成与前…...
Java 二维码
Java 二维码 **技术:**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...
Python ROS2【机器人中间件框架】 简介
销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...

让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比
在机器学习的回归分析中,损失函数的选择对模型性能具有决定性影响。均方误差(MSE)作为经典的损失函数,在处理干净数据时表现优异,但在面对包含异常值的噪声数据时,其对大误差的二次惩罚机制往往导致模型参数…...

MySQL 知识小结(一)
一、my.cnf配置详解 我们知道安装MySQL有两种方式来安装咱们的MySQL数据库,分别是二进制安装编译数据库或者使用三方yum来进行安装,第三方yum的安装相对于二进制压缩包的安装更快捷,但是文件存放起来数据比较冗余,用二进制能够更好管理咱们M…...

GitFlow 工作模式(详解)
今天再学项目的过程中遇到使用gitflow模式管理代码,因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存,无论是github还是gittee,都是一种基于git去保存代码的形式,这样保存代码…...