【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的区别,从底层机制、…...

4.Mybatis中,在Mapper的SQL映射文件中,使用<choose><when>无法识别参数的情况
正确结果 <?xml version"1.0" encoding"UTF-8" ?> <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace"com.itheima.mapper.Bra…...

antd proFromSelect 懒加载+模糊查询
antd proFromSelect 懒加载模糊查询 场景 查询用户的时候数量特别大,有10w条数据,不可能直接全部查询用来展示 所以本文章将讲解如何使用懒加载模糊查询,解决数量过大的问题 后端代码就不用展示了,很简单的分页查询,主…...

Spring Boot 牛刀小试 org.springframework.boot:spring-boot-maven-plugin:找不到类错误
今天看了下书翻了下Spring Boot的用法,下载idea后, 反复出现org.springframework.boot:spring-boot-maven-plugin:找不到类错误,后来看了下调试窗口,发现是连不上maven的网站443错误,解决思路很简单,把ide连…...

qt中ctrl+鼠标左键无法进入
现象:qt中ctrl鼠标左键无法跳转部分函数,例如能跳到textEdit->toPlainText().,但无法跳转到toUtf8();但编译没有问题 排查1:我发现是交叉编译链的问题,使用linux自带就可以进,用ATK-I.MX6U就部分不能进…...

丹摩征文活动 | 丹摩智算平台:服务器虚拟化的璀璨明珠与实战秘籍
丹摩DAMODEL|让AI开发更简单!算力租赁上丹摩! 目录 一、引言 二、丹摩智算平台概述 (一)平台架构 (二)平台特点 三、服务器虚拟化基础 (一)虚拟化的概念 …...

本机ip地址和网络ip地址一样吗
在数字化时代的浪潮中,IP地址作为网络设备身份的象征,扮演着举足轻重的角色。然而,当我们谈论IP地址时,常常会听到“本机IP地址”与“网络IP地址”这两个术语,它们之间是否存在差异?又该如何准确理解并区分…...

websocket身份验证
websocket身份验证 前言 上一集我们就完成了websocket初始化的任务,那么我们完成这个内容之后就应该完成一个任务,当客户端与服务端连接成功之后,客户端应该主动发起一个身份认证的消息。 身份认证proto 我们看一眼proto文件的内容。 我…...

案例解读 | 某三甲医院IT监控体系升级实例
PART 01 项目背景 01客户介绍 案例医院是一家某省省属大型三级甲等综合医院。该医院占地三百余亩,总建筑面积约26万平方米,开放床位1500张,资产总值约15亿元,其规划建设一流,拥有诸多先进配套设施,建设项目…...

Ubuntu20.04 为脚本文件创建桌面快捷方式 ubuntu
Ubuntu20.04 为脚本文件创建桌面快捷方式 在Ubuntu 20.04中,为脚本文件(如 .sh 文件)创建桌面快捷方式是一种提升用户效率的实用方法,允许用户通过图形用户界面直接执行重要或常用的脚本。以下是一种详细、专业且逻辑清晰的通用方…...

LeetCode297.二叉树的序列化和反序列化
题目要求 序列化是将一个数据结构或者对象转换为连续的比特位的操作,进而可以将转换后的数据存储在一个文件或者内存中,同时也可以通过网络传输到另一个计算机环境,采取相反方式重构得到原数据。 请设计一个算法来实现二叉树的序列化与反序…...