Java反射全面详解
1. 什么是反射?
首先听这个名字就有些疑惑,什么是反射,它能用来干什么呢?
Java官方对反射的解释是 "反射允许对封装类的字段,方法和构造函数进行编程式访问"。这里的字段指的就是成员变量,方法指的就是成员方法,构造函数就是构造方法。
2. 反射有什么用?
我们知道,在类中,常用的有字段,构造方法,成员方法。我们的反射就是可以把一个类中所有的字段,构造方法,成员方法全部都获取出来。那么问题又来了,获取出来有什么用呢?
反射用途还是很多的,我们熟知的IDEA开发工具,他可以在我们编写代码时自动给出提示,提示我们有哪些方法可以用,有哪些构造器可以使用,它是怎么做到的呢?说到这里,不难猜出,它其实就是用的反射。
还有如下所示,我们 new 一个对象,但忘记了它可以传递哪些参数,这个时候我们按键盘上的 Ctrl + P 键,它就会自动弹出提示我们需要传递哪些参数,这个其实也使用反射做到的。
刚才我们说到了, 反射就是可以把一个类中所有的字段,构造方法,成员方法全部都获取出来。
不仅如此,通过反射我们可以获取的非常全面,非常详细,我们甚至可以获取到。
当我们获取字段(变量)时,不仅可以获取到该变量,还能获取到该变量的访问修饰符,名字,类型,并可以为它赋值或者获取初始值;
当我们获取构造方法时,不仅可以获取到构造方法,还能获取到修饰符,名字,形参,还可以创建对象;
当我们获取成员方法时,不仅可以获取到成员方法,也能获取到该方法的修饰符,名字,形参,还能获取方法的返回值,抛出的异常,以及方法上的注解也能获取到,可以说是有什么就能获取到什么,一点不剩的全都可以拿到。
此外有一点要知道,我们获取字段,构造方法,成员方法不是通过Java文件来获取的,而是通过 Class 字节码文件中获取的。
总的来说可以理解为一句话:通过反射我们可以获取到类中的所有信息。
3. 获取 Class 字节码文件对象的三种方式(重中之重,面试会问)
3.1 Class.forName("全类名")方式获取;
其实这种方式应该并不陌生,如果有小伙伴学过JDBC的,应该都大致了解过,通过Class.forName("com.mysql.jdbc.Driver")来获取该类的字节码文件对象。
下面我简单演示一下吧
如下是一个JavaBean类 Account
package cn.itcast.user.pojo;import java.io.Serializable;public class Account implements Serializable {private static final long serialVersionUID = -421643127452356642L;// 账户idprivate Integer accountId;// 账户人名称private String accountName;// 账户密码private transient String accountPassword;public Account(Integer accountId, String accountName, String accountPassword) {this.accountId = accountId;this.accountName = accountName;this.accountPassword = accountPassword;}public Account() {}@Overridepublic String toString() {return "Account{" +"accountId=" + accountId +", accountName='" + accountName + '\'' +", accountPassword='" + accountPassword + '\'' +'}';}public Integer getAccountId() {return accountId;}public void setAccountId(Integer accountId) {this.accountId = accountId;}public String getAccountName() {return accountName;}public void setAccountName(String accountName) {this.accountName = accountName;}public String getAccountPassword() {return accountPassword;}public void setAccountPassword(String accountPassword) {this.accountPassword = accountPassword;}
}
然后我定义一个 main 方法,通过 Class.forName() 的方式来获取,代码如下
public static void main(String[] args) {// 这里可能或出现异常,由于是 main 方法中,最好用 try。。。catch,,,捕获try {System.out.println(Class.forName("cn.itcast.user.pojo.Account"));;} catch (ClassNotFoundException e) {e.printStackTrace();}}
我们直接运行此方法,就可以在控制台得到 Account 类的字节码文件对象,如下所示
3.2 类名.class 方式获取
操作方法如下代码
可以看到也没有任何问题,我就不多做解释了;
3.3 对象.getClass() 方式获取
这里必须是想要反射的类的对象,谁调用getClass,得到的就是谁的类对象。如下代码展示
还有一点可以注意一下,getClass() 方法是定义在 Obeject 类中的,所以所有的对象都可以使用此方法。
3.4 三种方式的通常应用场景
如果我想创建一个类的对象,分为以下三种阶段,每一个阶段都有它适当使用的场景。
阶段一:编写Java文件,将Java文件编写成字节码文件,这个阶段也被称为源代码阶段,可以使用 Class.forName() 的方式来获取;
阶段二:当我们把字节码文件加载到内存中准备运行的时候,可以称为加载阶段,这个阶段通常采用 类名.class 的方式获取字节码文件对象;
阶段三:在内存中运行时,我可以创建类对象,这个阶段也被称为运行阶段,通常采用 对象.getClass() 的方式获取字节码文件对象;
4. 利用反射获取构造方法
获取类的字节码文件之后,我们就可以通过字节码文件对象获取构造方法,我们可以获取单个构造器,可以获取所有构造器,还能创建对象。
如下图所示,即为获取构造方法的方法,我们简单测试一下;
如下代码,实体类 Account,我定义了多个构造器,注释如下
public class Account implements Serializable {private static final long serialVersionUID = -421643127452356642L;// 账户idprivate Integer accountId;// 账户人名称private String accountName;// 账户密码private transient String accountPassword;// 全参构造器public Account(Integer accountId, String accountName, String accountPassword) {this.accountId = accountId;this.accountName = accountName;this.accountPassword = accountPassword;}// 一个参数的构造器public Account(Integer accountId) {this.accountId = accountId;}// 两个参数的构造器public Account(Integer accountId, String accountName) {this.accountId = accountId;this.accountName = accountName;}// 无参构造器public Account() {}
}
然后我们去 main 方法中测试通过反射获取构造器,代码和注释如下
public class Test01{public static void main(String[] args) {// 需要先定义一个 Account 类的对象Account account = new Account();// 根据对象获取类的字节码文件Class clazz = account.getClass();try {// 获取参数类型为 Integer 的构造器Constructor con = clazz.getConstructor(Integer.class);// 打印输出该构造器System.out.println(con);} catch (NoSuchMethodException e) {e.printStackTrace();}System.out.println("----------------------------------------------");// 构造器本身也是一个对象,这里我们获取多个构造器,用列表进行接收Constructor[] constructors = clazz.getConstructors();// 输出获取到的所有构造器System.out.println(constructors);}
}
运行 main 方法,得到如下结果
在获取到类的字节码文件之后,我们不仅可以向上面那样获取到构造方法,还可以获取到更为详细的信息
在上图中可以看到,IDEA给出了大量的提示,我挑几个来说一下可以干什么
getParameterConunt() 获取参数个数;
getParameterTypes() 获取参数类型;
getParameter() 获取所有参数;
getModifiers() 获取该方法的权限修饰符,如 public,private,但返回的值是整数,如果返回1,则说明为public,若返回2,则为private。
看他们的英文名字就能大概了解了,我们的IDEA自动提示功能就是通过这些功能来做到的!
5. 利用反射获取属性
利用反射我们也可以获取到类中的属性,例如刚才的 Account 类,我们可以获取到它的 账户id,账户名称,账户密码等属性,相应方法如下所示
我们还是需要先获取类的字节码文件,再通过字节码文件的方法获取类中的属性,如下所示
我这里是获取所有的,当然也可以获取单个的,将方法的后缀 s 去掉就可调用获取单个属性的方法,它也和刚才的构造方法一样,可以获取属性的修饰符,还可以获取到属性的变量名,这里就不重复演示了。
6. 通过反射获取成员方法
如下图中所示的即为获取成员方法的方法,我们也是要通过字节码文件对象来获取
我们把刚才的 Account 类添加上 get和set方法
通过字节码文件即可获取 get 和 set 方法
还有几个方法我就不一一展示了,也都不难。
其实反射这一章在开发时并不常用,他们主要是应用与框架,如果以后你自己也开发框架的话,会经常用到反射。
另外,获取Class字节码文件的三种方法是面试时常常问到的一个点,各位需要好好记住。
相关文章:

Java反射全面详解
1. 什么是反射? 首先听这个名字就有些疑惑,什么是反射,它能用来干什么呢? Java官方对反射的解释是 "反射允许对封装类的字段,方法和构造函数进行编程式访问"。这里的字段指的就是成员变量,方法…...

助力工业物联网,工业大数据之费用事实指标分析及实现【二十四】
文章目录 1:费用事实指标分析及实现2:差旅事实指标分析及实现3:网点物料事实指标分析及实现 1:费用事实指标分析及实现 目标:实现DWB层费用报销事实指标表的构建 路径 step1:目标需求step2:数据…...

Istio 安全 mTLS认证 PeerAuthentication
这里定义了访问www.ck8s.com可以使用http也可以使用https访问,两种方式都可以访问。 那么是否可以强制使用mtls方式去访问? mTLS认证 PeerAuthentication PeerAuthentication的主要作用是别人在和网格里的pod进行通信的时候,是否要求mTLS mTL…...

【MySQL】数据库基本使用
文章目录 一、数据库介绍二、数据库使用2.1 登录MySQL2.2 基本使用2.2.1 显示当前 MySQL 实例中所有的数据库列表2.2.2 创建数据库2.2.3 创建数据库表2.2.4 在表中插入数据2.2.5 在表中查询数据 三、服务器、数据库、表之间的关系四、SQL语句分类五、存储引擎 一、数据库介绍 …...
计算shell脚本执行的时间
我们在使用shell脚本进行一些批量活动的时候,在有的场景下会需要知道脚本执行用了多长的时间,一谈到这个话题,我们一般的想法就是记录时间再开始阶段,执行完成后再记录时间,然后求时间差,这样是可以的&…...
无网络环境下,如何部署Docker镜像
无网络环境下,如何部署Docker镜像 什么是Docker镜像 Docker镜像是Docker容器的基础构建块。它是一个轻量级、独立且可执行的软件包,其中包含了运行应用程序所需的所有文件系统、代码、依赖关系和配置。 Docker镜像由一系列只读层(Layers&a…...

瑞吉外卖项目----(2)缓存优化
1 缓存优化 1.0 问题说明 1.1 环境搭建 将项目推送到远程仓库里,教程在git 提交远程仓库前建议取消代码检查 创建新的分支v1.0(用于实现缓存优化)并推送到远程仓库 1.1.1 maven坐标 导入spring-data-redis的maven坐标: &l…...
c++ http url encode decode
在C++中,可以使用以下方法对URL进行编码和解码: URL编码:#include <iostream> #include <string> #include <sstream> #include <iomanip>std::string urlEncode...
@vue/composition-api功能介绍
前言 vue/composition-api 是通过一个插件的方式,为 Vue2(2.7自带,2.6及以下可用) 提供类似 Vue3 composition API 的函数式编程能力。它的实现思路主要有: 1、提供组合式函数,在函数内部追踪响应性依赖。 2、将组合产生的响应式状态保存到…...
WebSocket整合直播
由于浏览器不支持对于rtmp协议推拉流,所以需要后台对传输的数据进行处理,将数据转接,为了实现其实时性,使用websocket将数据传输 先使用obs和vlc测试正常的推拉流是否正常 然后在跑本地后台传输视频 使用JavaCV技术传输音视频 …...

【Linux】IO 篇:文件调用原理,文件描述符,FILE的内涵,解析重定向,理解缓冲区
文章目录 一、系统调用接口二、文件调用1. 文件描述符 fd2. 文件调用原理3. FILE 三、重定向dup2 四、缓冲区简易 FILE 的代码实现 文件被加载之前,被存在磁盘上,操作文件,文件的部分内容则会被调度到 内存中。 要分析文件,我们也…...
力扣:47. 全排列 II(Python3)
题目: 给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。 来源:力扣(LeetCode) 链接:力扣 示例: 示例 1: 输入:nums [1,1,2] 输出:[…...
Android uart-修改串口节点名
需求: 应客户软件的需求,需要将Android系统里面的/dev/ttyS3节点名称修改为/dev/ttyS9; 实现: 1、判断 driver->name是否为"ttyS",index是否为3,如果是的话替换为ttyS9; diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c old mode 100644 new …...

【HarmonyOS】键盘遮挡输入框时,实现输入框显示在键盘上方
【关键字】 harmonyOS、键盘遮挡input,键盘高度监听 【写在前面】 在使用API6、API7开发HarmonyOS应用时,常出现页面中需要输入input,但是若input位置在页面下方,在input获取焦点的时候,会出现软键盘挡住input情况&a…...
day19-二叉树的最大最小深度
二叉树的最大/最小深度 给定一个二叉树 root ,返回其最大/小深度。 二叉树的 最大/小深度 是指从根节点到最远/近叶子节点的最长路径上的节点数。 思路 求最大深度比较简单,我们先解决最大深度。 最大深度 递归 class Solution { public:int maxD…...
Ansible-roles
Ansible-roles 一、roles作用 把playbook剧本里的各个play看作为角色,将各个角色的tasks任务、vars变量、templates模板、files文件等内容放置到角色的目录中统一管理,需要的时候可在playbook中直接使用roles调用,所以roles可以实现playboo…...

NullPointerException导致手机重启案例分析
和你一起终身学习,这里是程序员Android 经典好文推荐,通过阅读本文,您将收获以下知识点: 一、 Framework 层对象 空指针导致手机重启。二、解决方案,规避空指针三、Telecom APK 控制导致的重启举例 一、 Framework 层对象 空指针导…...

JAVA 反编译工具
Releases deathmarine/Luyten GitHub 安装exe 打开拖入文件即可...
(AcWing)分组背包问题
有 N 组物品和一个容量是 V 的背包。 每组物品有若干个,同一组内的物品最多只能选一个。 每件物品的体积是 vij,价值是 wij,其中 i 是组号,j 是组内编号。 求解将哪些物品装入背包,可使物品总体积不超过背包容量&…...

JSP项目国际化词条统计
国际化字条匹配并导出为excel格式 需求 将jsp页面里的key值,就是<spring:message code"gsyezer_Single_crystal"/>里的gsyezer_Single_crystal。和对应的字条对应上,并以excel表格形式输出。 jsp页面key值示例 <label for"&…...

调用支付宝接口响应40004 SYSTEM_ERROR问题排查
在对接支付宝API的时候,遇到了一些问题,记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...

相机Camera日志实例分析之二:相机Camx【专业模式开启直方图拍照】单帧流程日志详解
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了: 这一篇我们开始讲: 目录 一、场景操作步骤 二、日志基础关键字分级如下 三、场景日志如下: 一、场景操作步骤 操作步…...

QT: `long long` 类型转换为 `QString` 2025.6.5
在 Qt 中,将 long long 类型转换为 QString 可以通过以下两种常用方法实现: 方法 1:使用 QString::number() 直接调用 QString 的静态方法 number(),将数值转换为字符串: long long value 1234567890123456789LL; …...
Element Plus 表单(el-form)中关于正整数输入的校验规则
目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入(联动)2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...

如何在网页里填写 PDF 表格?
有时候,你可能希望用户能在你的网站上填写 PDF 表单。然而,这件事并不简单,因为 PDF 并不是一种原生的网页格式。虽然浏览器可以显示 PDF 文件,但原生并不支持编辑或填写它们。更糟的是,如果你想收集表单数据ÿ…...
Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信
文章目录 Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket(服务端和客户端都要)2. 绑定本地地址和端口&#x…...
C++课设:简易日历程序(支持传统节假日 + 二十四节气 + 个人纪念日管理)
名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 专栏介绍:《编程项目实战》 目录 一、为什么要开发一个日历程序?1. 深入理解时间算法2. 练习面向对象设计3. 学习数据结构应用二、核心算法深度解析…...

并发编程 - go版
1.并发编程基础概念 进程和线程 A. 进程是程序在操作系统中的一次执行过程,系统进行资源分配和调度的一个独立单位。B. 线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。C.一个进程可以创建和撤销多个线程;同一个进程中…...
嵌入式常见 CPU 架构
架构类型架构厂商芯片厂商典型芯片特点与应用场景PICRISC (8/16 位)MicrochipMicrochipPIC16F877A、PIC18F4550简化指令集,单周期执行;低功耗、CIP 独立外设;用于家电、小电机控制、安防面板等嵌入式场景8051CISC (8 位)Intel(原始…...
[特殊字符] 手撸 Redis 互斥锁那些坑
📖 手撸 Redis 互斥锁那些坑 最近搞业务遇到高并发下同一个 key 的互斥操作,想实现分布式环境下的互斥锁。于是私下顺手手撸了个基于 Redis 的简单互斥锁,也顺便跟 Redisson 的 RLock 机制对比了下,记录一波,别踩我踩过…...