java反射学习总结
最近在项目上有一个内部的CR,运用到了反射。想起之前面试的时候被面试官追问有没有在项目中用过反射,以及反射的原理和对反射的了解。
于是借此机会,学习回顾一下反射,以及在项目中可能会用到的场景。
Java 中的反射概述
反射(Reflection) 是 Java 提供的一种机制,它允许程序在运行时动态地检查和操作类的属性、方法以及构造函数等信息。反射使得我们可以在编译时不确定类型的情况下操作对象,比如动态地调用方法、访问属性和创建对象实例。
反射的核心类和接口
反射主要依赖于以下几个类和接口:
- Class<?>:代表一个类的字节码对象,通过它可以获取类的名称、方法、字段、构造函数等信息。
- Field:表示类的属性,可以通过它获取或修改某个对象的字段值。
- Method:表示类的方法,可以通过它调用类的某个方法。
- Constructor<?>:表示类的构造函数,可以通过它创建类的实例。
反射的主要功能
- 获取类的结构信息:包括类名、包名、父类、实现的接口等。
- 获取类的成员信息:包括属性(Field)、方法(Method)、构造函数(Constructor)等。
- 动态操作对象:包括创建实例、调用方法、修改属性值等。
反射的常用方法
获取类对象 :
Class<?> clazz = Class.forName("com.example.MyClass"); // 通过类的全限定名获取
Class<?> clazz = MyClass.class; // 通过类名.class获取
Class<?> clazz = object.getClass(); // 通过对象实例获取
获取类的构造函数:
Constructor<?> constructor = clazz.getConstructor(); // 获取无参构造函数
Constructor<?> constructor = clazz.getConstructor(String.class); // 获取带参数的构造函数
Object instance = constructor.newInstance("arg"); // 创建类的实例
获取类的方法:
Method method = clazz.getMethod("methodName", String.class); // 获取特定名称和参数的方法
method.invoke(instance, "arg"); // 调用方法
获取类的属性:
Field field = clazz.getDeclaredField("fieldName"); // 获取特定名称的属性
field.setAccessible(true); // 设置可访问性,忽略private修饰符
field.set(instance, "value"); // 设置属性值
反射的应用场景
- 依赖注入(Dependency Injection:如 Spring 框架,通过反射机制在运行时动态地为类的属性赋值,完成依赖注入。
- 框架设计(如ORM框架:如 Hibernate,通过反射获取实体类的字段和方法,将数据库表和实体类进行映射。
- 动态代理(Dynamic Proxy:通过反射生成代理类,增强方法的功能,应用于 AOP(面向切面编程)等。
- 运行时动态操作:在运行时根据配置文件或用户输入动态调用指定的方法,常用于插件化、动态加载等场景。
- 测试框架(如JUnit:JUnit 等测试框架通过反射来调用测试方法,并通过反射访问私有成员变量以便进行单元测试。
反射的原理
每个 Java 类在被加载时,JVM 会为该类生成一个唯一的
Class
对象,这个对象包含了类的所有元数据信息,如类名、包名、父类、接口、构造方法、字段、方法等。反射机制的基础就是利用Class
对象来获取这些信息。
反射的基本操作流程
- 获取 Class 对象:反射的第一步是获取代表某个类的 Class 对象。可以通过 Class.forName()、类名.class 或 对象.getClass() 来获取。
Class
对象是所有反射操作的基础。JVM 会为每一个被加载的类创建一个Class
对象,Class
对象中存储了该类的所有元数据信息。
Class.forName(String className)
:通过类的全限定名在运行时加载类并返回其Class
对象。类名.class
:直接通过类名获取该类的Class
对象。对象.getClass()
:通过对象实例获取其对应的Class
对象。这些方法调用后都会返回 JVM 中已经存在的
Class
对象,而不会重新加载类。
- 获取类的成员信息:通过 Class 对象的各种方法如 getDeclaredMethods()、getDeclaredFields() 等,可以获取类的所有方法、字段、构造函数等信息。
Class 对象中包含了类的所有元数据信息,可以通过以下方法获取:
//获取字段信息(Field): Constructor<?> constructor = clazz.getDeclaredConstructor(参数类型.class); //获取方法信息(Method): Method method = clazz.getDeclaredMethod("methodName", 参数类型.class); //获取构造函数信息(Constructor): Field field = clazz.getDeclaredField("fieldName");
Field、Method 和 Constructor 对象中都包含了对应的详细信息(名称、类型、修饰符等),这些信息是 JVM 在类加载时解析字节码并存储在 Class 对象中的。
- 动态操作:获取到类的结构信息后,可以通过 Method.invoke() 调用方法,通过 Field.set() 或 Field.get() 修改或访问字段,通过 Constructor.newInstance() 创建实例等。
调用方法:
Method method = clazz.getDeclaredMethod("methodName", 参数类型.class); method.setAccessible(true); // 如果方法是私有的,需要设置可访问性 Object result = method.invoke(instance, 参数); // 动态调用方法
反射调用方法的过程大致如下:
- 检查方法的可访问性,如果是私有方法则需要设置
setAccessible(true)
。- 解析方法的参数类型,并匹配传递的参数是否符合要求。
- 调用
invoke
时,JVM 通过内部调用找到对应的本地方法实现,然后执行调用。修改字段值:
Field field = clazz.getDeclaredField("fieldName"); field.setAccessible(true); // 如果字段是私有的,需要设置可访问性 field.set(instance, value); // 动态修改字段值
修改字段值的过程:
- 检查字段的可访问性,如果是私有字段则需要设置
setAccessible(true)
。- 调用
set()
时,JVM 将新值赋给对象的相应字段。创建对象实例:
Constructor<?> constructor = clazz.getDeclaredConstructor(参数类型.class); constructor.setAccessible(true); // 如果构造函数是私有的,需要设置可访问性 Object instance = constructor.newInstance(参数); // 动态创建实例
创建对象实例的过程:
- 检查构造函数的可访问性,如果是私有构造函数则需要设置
setAccessible(true)
。- 调用
newInstance()
时,JVM 内部调用本地方法创建对象,并初始化实例。
反射的局限性和问题
-
性能问题: 反射在运行时解析类的元数据,因此其性能相对直接调用方法要低。频繁使用反射可能导致较大的性能开销。
-
安全性问题: 反射可以绕过 Java 的访问控制检查,访问和修改类的私有成员。这可能导致安全隐患,特别是在不受信任的环境中。
-
编译时类型检查缺失: 反射依赖于运行时类型信息,编译器无法对反射代码进行类型检查。这意味着在编译时可能无法检测出反射调用中的错误,只有在运行时才会抛出异常。
面对反射造成的错误该如何解决
-
ClassNotFoundException
:类无法找到。- 确保类名(包括包名)拼写正确。
- 确保类在类路径中存在。
-
NoSuchMethodException
/NoSuchFieldException
:方法或字段不存在。- 检查方法名、字段名以及参数类型是否匹配。
- 确保访问的成员确实存在于目标类中。
-
IllegalAccessException
:非法访问异常。- 确保
setAccessible(true)
已调用。 - 确保 JVM 安全管理器允许修改私有成员。
- 确保
-
InvocationTargetException
:目标方法内部抛出异常。- 调用
getCause()
获取实际异常,并检查目标方法内部的逻辑。
- 调用
-
InstantiationException
:无法实例化对象。- 检查是否试图实例化一个抽象类或接口。
- 确保存在无参构造函数,或使用带参构造函数。
总结
反射机制是 Java 强大的动态编程功能之一,它允许我们在运行时检查和操作类的结构信息,这在构建灵活的框架和库时非常有用。然而,反射的使用会带来一定的性能和安全性问题,因此在使用时应尽量避免过度使用。理解反射的内部实现原理和应用场景,掌握应对反射相关错误的解决方法,可以更好地利用这一特性来解决实际问题
相关文章:
java反射学习总结
最近在项目上有一个内部的CR,运用到了反射。想起之前面试的时候被面试官追问有没有在项目中用过反射,以及反射的原理和对反射的了解。 于是借此机会,学习回顾一下反射,以及在项目中可能会用到的场景。 Java 中的反射概述 反射&…...

探索C语言与Linux编程:获取当前用户ID与进程ID
探索C语言与Linux编程:获取当前用户ID与进程ID 一、Linux系统概述与用户、进程概念二、C语言与系统调用三、获取当前用户ID四、获取当前进程ID五、综合应用:同时获取用户ID和进程ID六、深入理解与扩展七、结语在操作系统与编程语言的交汇点,Linux作为开源操作系统的典范,为…...

1.4 边界值分析法
欢迎大家订阅【软件测试】 专栏,开启你的软件测试学习之旅! 文章目录 前言1 定义2 选取3 具体步骤4 案例分析 本篇文章参考黑马程序员 前言 边界值分析法是一种广泛应用于软件测试中的技术,旨在识别输入值范围内的潜在缺陷。本文将详细探讨…...
Spring IOC容器Bean对象管理-注解方式
目录 1、Bean对象常用注解介绍 2、注解示例说明 1、Bean对象常用注解介绍 Component 通用类组件注解,该类被注解,IOC容器启动时实例化此类对象Controller 注解控制器类Service 注解业务逻辑类Respository 注解和数据库操作的类,如DAO类Reso…...

OpenAI API: How to catch all 5xx errors in Python?
题意:OpenAI API:如何在 Python 中捕获所有 5xx 错误? 问题背景: I want to catch all 5xx errors (e.g., 500) that OpenAI API sends so that I can retry before giving up and reporting an exception. 我想捕获 OpenAI API…...

C++初阶学习——探索STL奥秘——标准库中的priority_queue与模拟实现
1.priority_queque的介绍 1.priority_queue中文叫优先级队列。优先队列是一种容器适配器,根据严格的弱排序标准,它的第一个元素总是它所包含的元素中最大的。 2. 此上下文类似于堆,在堆中可以随时插入元素,并且只能检索最大堆元…...
PyTorch经典模型
PyTorch 经典模型教程 1. PyTorch 库架构概述 PyTorch 是一个广泛使用的深度学习框架,具有高度的灵活性和动态计算图的特性。它支持自动求导功能,并且拥有强大的 GPU 加速能力,适用于各种神经网络模型的训练与部署。 PyTorch 的核心架构包…...

C++ STL容器(三) —— 迭代器底层剖析
本篇聚焦于STL中的迭代器,同样基于MSVC源码。 文章目录 迭代器模式应用场景实现方式优缺点 UML类图代码解析list 迭代器const 迭代器非 const 迭代器 vector 迭代器const 迭代器非const迭代器 反向迭代器 迭代器失效参考资料 迭代器模式 首先迭代器模式是设计模式中…...
力扣416周赛
举报垃圾信息 题目 3295. 举报垃圾信息 - 力扣(LeetCode) 思路 直接模拟就好了,这题居然是中等难度 代码 public boolean reportSpam(String[] message, String[] bannedWords) {Map<String,Integer> map new HashMap<>()…...
vue 页面常用图表框架
在 Vue.js 页面中,常见的用于制作图表的框架或库有以下几种: ECharts: 官方网站: EChartsECharts 是一个功能强大、可扩展的图表库,支持多种图表类型,如柱状图、折线图、饼图等。Vue 集成: 可以使用 vue-echarts 插件,…...
spring 注解 - @PostConstruct - 用于初始化工作
PostConstruct 是 Java EE 5 中引入的一个注解,用于标注在方法上,表示该方法应该在依赖注入完成之后执行。这个注解是 javax.annotation 包的一部分,通常用于初始化工作,比如初始化成员变量或者启动一些后台任务。 在 Spring 框架…...

多机器学习模型学习
特征处理 import os import numpy as np import pandas as pd from sklearn.model_selection import train_test_split from sklearn.model_selection import StratifiedShuffleSplit from sklearn.impute import SimpleImputer from sklearn.pipeline import FeatureUnion fr…...
【网页设计】前言
本专栏主要记录 “网页设计” 这一课程的相关笔记。 参考资料: 黑马程序员:黑马程序员pink老师前端入门教程,零基础必看的h5(html5)css3移动端前端视频教程_哔哩哔哩_bilibili 教材:《Adobe创意大学 Dreamweaver CS6标准教材》《…...

STM32巡回研讨会总结(2024)
前言 本次ST公司可以说是推出了7大方面,几乎可以说是覆盖到了目前生活中的方方面面,下面总结下我的感受。无线类 支持多种调制模式(LoRa、(G)FSK、(G)MSK 和 BPSK)满足工业和消费物联网 (IoT) 中各种低功耗广域网 (LPWAN) 无线应…...

54 螺旋矩阵
解题思路: \qquad 这道题可以直接用模拟解决,顺时针螺旋可以分解为依次沿“右-下-左-上”四个方向的移动,每次碰到“边界”时改变方向,边界是不可到达或已经到达过的地方,会随着指针移动不断收缩。 vector<int>…...
基于STM32与OpenCV的物料搬运机械臂设计流程
一、项目概述 本文提出了一种新型的物流搬运机器人,旨在提高物流行业的物料搬运效率和准确性。该机器人结合了 PID 闭环控制算法与视觉识别技术,能够在复杂的环境中实现自主巡线与物料识别。 项目目标与用途 目标:设计一款能够自动搬运物流…...

[万字长文]stable diffusion代码阅读笔记
stable diffusion代码阅读笔记 获得更好的阅读体验可以转到我的博客y0k1n0的小破站 本文参考的配置文件信息: AutoencoderKL:stable-diffusion\configs\autoencoder\autoencoder_kl_32x32x4.yaml latent-diffusion:stable-diffusion\configs\latent-diffusion\lsun_churches-ld…...
watchEffect工作原理
watchEffect工作原理 自动依赖收集:watchEffect不需要明确指定要观察的响应式数据,它会自动收集回调函数中用到的所有响应式数据作为依赖。即时执行:watchEffect的回调函数会在组件的setup()函数执行时立即执行一次,以便能够立即…...
斐波那契数列
在 Python 3.11 中实现斐波那契数列的常见方式有多种,下面我将展示几种不同的实现方法,包括递归、迭代和使用缓存(动态规划)来优化递归版本。 1. 递归方式(最简单但效率较低) def fibonacci_recursive(n)…...

TCP并发服务器的实现
一请求一线程 问题 当客户端数量较多时,使用单独线程为每个客户端处理请求可能导致系统资源的消耗过大和性能瓶颈。 资源消耗: 线程创建和管理开销:每个线程都有其创建和销毁的开销,特别是在高并发环境中,这种开销…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)
HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...
java 实现excel文件转pdf | 无水印 | 无限制
文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...

Module Federation 和 Native Federation 的比较
前言 Module Federation 是 Webpack 5 引入的微前端架构方案,允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...
大数据学习(132)-HIve数据分析
🍋🍋大数据学习🍋🍋 🔥系列专栏: 👑哲学语录: 用力所能及,改变世界。 💖如果觉得博主的文章还不错的话,请点赞👍收藏⭐️留言Ǵ…...
代理篇12|深入理解 Vite中的Proxy接口代理配置
在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...
AGain DB和倍数增益的关系
我在设置一款索尼CMOS芯片时,Again增益0db变化为6DB,画面的变化只有2倍DN的增益,比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析: 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...
IP如何挑?2025年海外专线IP如何购买?
你花了时间和预算买了IP,结果IP质量不佳,项目效率低下不说,还可能带来莫名的网络问题,是不是太闹心了?尤其是在面对海外专线IP时,到底怎么才能买到适合自己的呢?所以,挑IP绝对是个技…...
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的“no matching...“系列算法协商失败问题
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的"no matching..."系列算法协商失败问题 摘要: 近期,在使用较新版本的OpenSSH客户端连接老旧SSH服务器时,会遇到 "no matching key exchange method found", "n…...

windows系统MySQL安装文档
概览:本文讨论了MySQL的安装、使用过程中涉及的解压、配置、初始化、注册服务、启动、修改密码、登录、退出以及卸载等相关内容,为学习者提供全面的操作指导。关键要点包括: 解压 :下载完成后解压压缩包,得到MySQL 8.…...