Java 反射机制详解
在 Java 编程世界中,反射机制犹如一把神奇的钥匙,它能够打开许多隐藏在代码深处的 “大门”,让开发者突破常规的限制,实现一些极具灵活性的功能。今天,就跟随我一同深入探究 Java 反射机制的奥秘。
一、什么是反射
反射是 Java 语言提供的一种强大机制,它允许程序在运行时动态地获取类的各种信息,比如类的成员变量、方法、构造函数等,并且能够实例化对象、调用方法以及访问和修改成员变量的值,而这些操作在编译期并不需要明确知道类的具体细节。
简单来说,正常情况下,我们编写代码时都是明确地引用类,例如创建一个类的对象:Person person = new Person(); 这里我们清楚知道 Person 类的结构。但反射却可以让我们在运行时才决定要操作哪个类,比如根据用户输入的类名去实例化相应的对象,就像拥有了动态操控代码的超能力。
二、反射的核心类
Java 反射机制主要依托于 java.lang.reflect 包下的几个核心类:
- Class 类:这是反射的入口,它代表一个类的运行时表示。每一个加载到 Java 虚拟机(JVM)中的类都有一个与之对应的 Class 对象,可以通过多种方式获取,例如 Class.forName("全限定类名")、类名.class 以及对象的 getClass() 方法。获取到 Class 对象后,就能以此为起点探索类的各种信息。
- Constructor 类:用于表示类的构造函数,可以通过 Class 对象获取类的所有构造函数,然后利用构造函数来创建类的实例,即使是私有的构造函数,反射也能访问并调用(当然,私有的构造函数通常有其特定的访问限制原因,滥用反射去调用可能破坏类的封装性)。
- Method 类:对应类的方法,能获取方法的签名、参数类型、返回值类型等信息,并且使用反射可以在对象上动态调用这些方法,就如同在运行时临时拼凑出方法调用的指令一样。
- Field 类:用来表示类的成员变量,通过它可以获取成员变量的类型、访问修饰符,以及读写成员变量的值,这意味着可以突破常规的访问权限控制,直接修改那些本应是私有的变量(不过同样要谨慎使用,以免造成难以排查的错误)。
三、反射的基本使用示例
(一)获取 Class 对象
以下是几种常见获取 Class 对象的方式:
// 方式一:使用 Class.forName(),常用于根据类名动态加载类
Class<?> clazz1 = Class.forName("com.example.demo.Person");
// 方式二:类名.class,常用于在已知类的情况下获取其 Class 对象,常用于参数传递等场景
Class<Person> clazz2 = Person.class;
// 方式三:通过对象的 getClass() 方法,获取该对象所属类的 Class 对象
Person person = new Person();
Class<? extends Person> clazz3 = person.getClass();
(二)创建实例
假设我们有一个简单的 Person 类:
public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// 省略 getters 和 setters
}
使用反射创建 Person 类实例:
try {
Class<?> personClass = Class.forName("com.example.demo.Person");
Constructor<?> constructor = personClass.getConstructor(String.class, int.class);
Person person = (Person) constructor.newInstance("张三", 20);
System.out.println(person.getName() + " : " + person.getAge());
} catch (Exception e) {
e.printStackTrace();
}
这里先获取到 Person 类的 Class 对象,接着拿到对应的构造函数,最后通过构造函数创建出实例。
(三)调用方法
继续以上述 Person 类为例,假设 Person 类有一个 sayHello 方法:
public void sayHello() {
System.out.println("Hello, I'm " + name);
}
使用反射调用该方法:
try {
Class<?> personClass = Class.forName("com.example.demo.Person");
Constructor<?> constructor = personClass.getConstructor(String.class, int.class);
Person person = (Person) constructor.newInstance("张三", 20);
Method method = personClass.getMethod("sayHello");
method.invoke(person);
} catch (Exception e) {
e.printStackTrace();
}
先创建实例,再获取 sayHello 方法对应的 Method 对象,最后通过 invoke 方法在实例上调用该方法。
(四)访问成员变量
还是针对 Person 类,访问其私有成员变量 name:
try {
Class<?> personClass = Class.forName("com.example.demo.Person");
Constructor<?> constructor = personClass.getConstructor(String.class, int.class);
Person person = (Person) constructor.newInstance("张三", 20);
Field field = personClass.getDeclaredField("name");
field.setAccessible(true); // 取消私有访问限制,这一步很关键,否则无法访问私有变量
String name = (String) field.get(person);
System.out.println("The name is: " + name);
} catch (Exception e) {
e.printStackTrace();
}
通过 getDeclaredField 获取成员变量,设置可访问后就能获取到变量的值。
四、反射的应用场景
(一)框架开发
像 Spring 这样的大型框架广泛使用反射机制。在依赖注入环节,框架需要根据配置文件或注解信息动态地创建类的实例、调用初始化方法等,将各个组件组装起来,而不用在编译时就硬编码所有的依赖关系,使得代码的扩展性和维护性大大增强。
(二)动态代理
实现 Java 的动态代理模式离不开反射。通过创建代理类,在运行时动态生成代理对象,代理对象能够拦截对目标对象方法的调用,添加额外的逻辑,如日志记录、权限验证等,然后再将方法调用转发给目标对象,这种动态生成代码逻辑的能力让程序更加灵活。
(三)插件化开发
一些支持插件扩展的应用,利用反射来加载外部的插件类。应用程序在运行时扫描指定目录下的插件 JAR 文件,通过反射将插件中的类加载进来,集成到主程序流程中,从而实现功能的动态扩展,用户无需重新编译整个应用就能添加新功能。
五、反射的优缺点
(一)优点
- 极大的灵活性:能够突破静态语言在编译期类型绑定的限制,根据运行时情况动态操作类,适应多变的业务需求。
- 利于框架构建:使得框架开发者可以编写通用的、高度抽象的代码,框架使用者只需按照约定配置,框架就能自动适配处理,提升开发效率。
(二)缺点
- 性能开销:相较于直接的静态代码调用,反射涉及动态解析类信息、查找方法等操作,会消耗更多的系统资源,导致程序运行效率降低,所以在对性能敏感的核心代码部分,要谨慎使用反射。
- 破坏封装性:反射可以访问类的私有成员,这虽然在某些场景下提供了便利,但也容易让代码的封装边界变得模糊,使得类的内部实现细节暴露在外,增加代码维护的难度和出错的风险。
相关文章:
Java 反射机制详解
在 Java 编程世界中,反射机制犹如一把神奇的钥匙,它能够打开许多隐藏在代码深处的 “大门”,让开发者突破常规的限制,实现一些极具灵活性的功能。今天,就跟随我一同深入探究 Java 反射机制的奥秘。 一、什么是反射 反…...
【k8s】scc权限 restricted、anyuid、privileged
文章目录 概述1. 内置的scc2. OpenShift如何确定pod的scc2.1 Pod未带SCC标签的情况2.2. Pod带有SCC标签的情况 参考 概述 在OpenShift(后文简称OCP)中,很早就一个概念:Security Context Constraints ,简称SCC…...
2025华数杯国际赛A题完整论文讲解(含每一问python代码+数据+可视化图)
大家好呀,从发布赛题一直到现在,总算完成了2025“华数杯”国际大学生数学建模竞赛A题Can He Swim Faster的完整的成品论文。 本论文可以保证原创,保证高质量。绝不是随便引用一大堆模型和代码复制粘贴进来完全没有应用糊弄人的垃圾半成品论文…...
ThreadLocal 的使用场景
在现代电商平台中,ThreadLocal 常用于以下场景,特别是与线程隔离相关的业务中,以提高性能和简化上下文传递。 1. 用户上下文信息管理 场景:在用户发起的每次请求中,需要携带用户 ID、角色、权限等信息,而这…...
后端开发 Springboot整合Redis Spring Data Redis 模板
目录 redis 配置 RedisConfig 类 完整代码 代码讲解 1. 类定义和注解 2. 定义 RedisTemplate Bean 3. 配置 JSON 序列化 4. 配置 Redis 的 key 和 value 序列化方式 5. 完成配置并返回 RedisTemplate 总结 redis 服务接口实现类 类级别 注入 RedisTemplate 常用 Re…...
代码随想录算法训练营第 4 天(链表 2)| 24. 两两交换链表中的节点19.删除链表的倒数第N个节点 -
一、24. 两两交换链表中的节点 题目:24. 两两交换链表中的节点 - 力扣(LeetCode) 视频:帮你把链表细节学清楚! | LeetCode:24. 两两交换链表中的节点_哔哩哔哩_bilibili 讲解:代码随想录 dummy-…...
【RDMA学习笔记】1:RDMA(Remote Direct Memory Access)介绍
从帝国理工的PPT学习。 什么是RDMA Remote Direct Memory Access,也就是Remote的DMA,是一种硬件机制,能直接访问远端结点的内存,而不需要处理器介入。 其中: Remote:跨node进行数据传输Directÿ…...
网络安全常见的35个安全框架及模型
大家读完觉得有帮助记得关注和点赞!!! 01、概述 网络安全专业机构制定的一套标准、准则和程序,旨在帮助组织了解和管理面临的网络安全风险。优秀的安全框架及模型应该为用户提供一种可靠方法,帮助其实现网络安全建设…...
Elasticsearch介绍及使用
Elasticsearch 是一款基于 Lucene 库构建的开源、分布式、RESTful 风格的搜索引擎和分析引擎,具有强大的全文搜索、数据分析、机器学习等功能,广泛应用于日志分析、实时数据分析、全文检索等场景。 核心概念 索引(Index)…...
Leetocde516. 最长回文子序列 动态规划
原题链接:Leetocde516. 最长回文子序列 class Solution { public:int longestPalindromeSubseq(string s) {int n s.size();vector<vector<int>> dp(n, vector<int>(n, 1));for (int i 0; i < n; i) {dp[i][i] 1;if (i 1 < n &&…...
iOS 逆向学习 - Inter-Process Communication:进程间通信
iOS 逆向学习 - Inter-Process Communication:进程间通信 一、进程间通信概要二、iOS 进程间通信机制详解1. URL Schemes2. Pasteboard3. App Groups 和 Shared Containers4. XPC Services 三、不同进程间通信机制的差异四、总结 一、进程间通信概要 进程间通信&am…...
高级生化大纲
一,蛋白质化学: 蛋白质分离是生物化学和分子生物学研究中的一项基本技术,用于根据蛋白质的物理和化学特性将其从混合物中分离出来。 1. 离心分离法 离心分离法利用离心力来分离不同质量或密度的颗粒和分子。 差速离心:通过逐…...
YARN WebUI 服务
一、WebUI 使用 与HDFS一样,YARN也提供了一个WebUI服务,可以使用YARN Web用户界面监视群集、队列、应用程序、服务、流活动和节点信息。还可以查看集群详细配置的信息,检查各种应用程序和服务的日志。 1.1 首页 浏览器输入http://node2.itc…...
【Unity3D】利用IJob、Burst优化处理切割物体
参考文章: 【Unity】切割网格 【Unity3D】ECS入门学习(一)导入及基础学习_unity ecs教程-CSDN博客 【Unity3D】ECS入门学习(十二)IJob、IJobFor、IJobParallelFor_unity ijobparallelfor-CSDN博客 工程资源地址&…...
【大前端】Vue3 工程化项目使用详解
目录 一、前言 二、前置准备 2.1 环境准备 2.1.1 create-vue功能 2.1.2 nodejs环境 2.1.3 配置nodejs的环境变量 2.1.4 更换安装包的源 三、工程化项目创建与启动过程 3.1 创建工程化项目 3.2 项目初始化 3.3 项目启动 3.4 核心文件说明 四、VUE两种不同的API风格 …...
基于文件系统分布式锁原理
分布式锁:在一个公共的存储服务上打上一个标记,如Redis的setnx命令,是先到先得方式获得锁,ZooKeeper有点像下面的demo,比较大小的方式判决谁获得锁。 package com.ldj.mybatisflex.demo;import java.util.*; import java.util.co…...
简历整理YH
一,订单中心 1,调拨单 融通(Rocketmq)-订单中心:ECC_BMS123(已出单),125(分配),127(发货),129(收货) 通过RocketMq接入多场景订单数据 2,销售单 sap(FTP)-订单中心,下发1002,1003,…...
Kotlin 协程基础三 —— 结构化并发(二)
Kotlin 协程基础系列: Kotlin 协程基础一 —— 总体知识概述 Kotlin 协程基础二 —— 结构化并发(一) Kotlin 协程基础三 —— 结构化并发(二) Kotlin 协程基础四 —— CoroutineScope 与 CoroutineContext Kotlin 协程…...
微信小程序实现长按录音,点击播放等功能,CSS实现语音录制动画效果
有一个需求需要在微信小程序上实现一个长按时进行语音录制,录制时间最大为60秒,录制完成后,可点击播放,播放时再次点击停止播放,可以反复录制,新录制的语音把之前的语音覆盖掉,也可以主动长按删…...
校园跑腿小程序---轮播图,导航栏开发
hello hello~ ,这里是 code袁~💖💖 ,欢迎大家点赞🥳🥳关注💥💥收藏🌹🌹🌹 🦁作者简介:一名喜欢分享和记录学习的在校大学生…...
详细全面讲解C++中重载、隐藏、覆盖的区别
文章目录 总结1、重载示例代码特点1. 模板函数和非模板函数重载2. 重载示例与调用规则示例代码调用规则解释3. 特殊情况与注意事项二义性问题 函数特化与重载的交互 2. 函数隐藏(Function Hiding)概念示例代码特点 3. 函数覆盖(重写ÿ…...
一文读懂单片机的串口
目录 串口通信的基本概念 串口通信的关键参数 单片机串口的硬件连接 单片机串口的工作原理 数据发送过程 数据接收过程 单片机串口的编程实现 以51单片机为例 硬件连接 初始化串口 发送数据 接收数据 串口中断服务函数 代码示例 单片机串口的应用实例 单片机与…...
HTML5 网站模板
HTML5 网站模板 参考 HTML5 Website Templates...
mybatis分页插件:PageHelper、mybatis-plus-jsqlparser(解决SQL_SERVER2005连接分页查询OFFSET问题)
文章目录 引言I PageHelper坐标II mybatis-plus-jsqlparser坐标Spring Boot 添加分页插件自定义 Mapper 方法中使用分页注意事项解决SQL_SERVER2005连接分页查询OFFSET问题知识扩展MyBatis-Plus 框架结构mybatis-plus-jsqlparser的 Page 类引言 PageHelper import com.github.p…...
uniapp中rpx和upx的区别
在 UniApp 中,rpx 和 upx 是两种不同的单位,它们的主要区别在于适用的场景和计算方式。 ### rpx(Responsive Pixel) - **适用场景**:rpx 是一种响应式单位,主要用于小程序和移动端的布局。 - **计算方式**…...
什么是卷积网络中的平移不变性?平移shft在数据增强中的意义
今天来介绍一下数据增强中的平移shft操作和卷积网络中的平移不变性。 1、什么是平移 Shift 平移是指在数据增强(data augmentation)过程中,通过对输入图像或目标进行位置偏移(平移),让目标在图像中呈现出…...
java.net.SocketException: Connection reset 异常原因分析和解决方法
导致此异常的原因,总结下来有三种情况: 一、服务器端偶尔出现了异常,导致连接关闭 解决方法: 采用出错重试机制 二、 服务器端和客户端使用的连接方式不一致 解决方法: 服务器端和客户端使用相同的连接方式ÿ…...
Maven 仓库的分类
Maven 是一个广泛使用的项目构建和依赖管理工具,在 Java 开发生态中占据重要地位。作为 Maven 的核心概念之一,仓库(Repository)扮演着至关重要的角色,用于存储项目的依赖、插件以及构建所需的各种资源。 了解 Maven 仓…...
隧道网络:为数据传输开辟安全通道
什么是隧道网络? 想象一下,你正在一个陌生的城市旅行,并且想要访问家里的电脑。但是,直接连接是不可能的,因为家庭网络通常受到防火墙或路由器的保护,不允许外部直接访问。这时候,隧道网络&…...
CentOS 7 下 Nginx 的详细安装与配置
1、安装方式 1.1、通过编译方式安装 下载Nginx1.16.1的安装包 https://nginx.org/download/nginx-1.16.1.tar.gz 下载后上传至/home目录下。 1.2、通过yum方式安装 这种方式安装更简单。 2、通过编译源码包安装Nginx 2.1、安装必要依赖 sudo yum -y install gcc gcc-c sudo…...
企管宝/seo在线培训
上篇介绍了.X文件网格的渲染方法,如果需要创建自己的网格文件,并将它渲染出来,那么可以考虑创建一个空的网格,然后读取网格文件内容,将顶点,材质和纹理数据写入以上的网格相关缓冲区中。创建一个自定义顶点…...
哈尔滨网站建设代理商/电子商务网站推广策略
1 <?php2 /**3 * 访问者模式4 *5 * 表示一个作用于某对象结构中的各元素的操作,可以在不改变各元素的类的前提下定义作用于这些元素的新操作6 *7 */8 abstractclassVisitor9 {10 abstractpublicfunctionvisitCroncreteElementA($element);11 abstractpublicfunctionvisitCr…...
百度地图怎么没有实景导航了/广州抖音seo公司
为什么80%的码农都做不了架构师?>>> 这个东西着挺有意思,用java实现一下 public static void main(String[] args){ printNum(1); } public static void printNum(int i){ System.out.println(i); int n i/(…...
安全网站建设与服务的关系/能够免费换友链的平台
转自:http://blog.csdn.net/xuelin273/article/details/38646765 usb热插拔,即usb设备可以实现即插即用,像U盘一样,插到电脑里就可以用,不用时可以直接拔除,这个动作不会影响USB设备使用性能。 在linx 系统…...
公司建设网站算入什么会计科目/云南网站建设百度
免费邮箱容量太小不适合办公,邮件刚破千就提示邮箱容量已满,有没有什么好办法可以解决这个问题呢?当然有的呀,今天就告诉大家邮箱容量满了如何解决?如何注册超大容量个人邮箱 邮箱容量满了如何解决? 我们…...