了解Java中的反射,带你如何使用反射
反射的定义
反射(Reflection)是Java的一种强大机制,它允许程序在运行时动态地查询和操作类的属性和方法。通过反射,Java程序可以获取类的信息,比如类的名称、方法、字段,以及可以动态地创建对象、调用方法和改变字段的值。
反射的主要用途包括:
- 动态加载类:在运行时加载类,而不需要在编译时确定。
- 查看类的结构:获取类的方法、字段、构造函数等信息,便于开发和调试。
- 实现通用代码:通过反射可以编写更为通用的代码,例如框架和库可以利用反射来实现插件或扩展机制。
- 访问和修改属性:可以在不知道对象具体类型的情况下,访问和修改其属性。
反射的实现一般通过Java的 java.lang.reflect
包进行,常用的类包括 Class
、Method
、Field
和 Constructor
等。使用反射需要注意性能开销和安全问题,因此在使用时要权衡其必要性。
反射的用途
反射在Java中的用途非常广泛,以下是一些主要的用途:
-
动态类加载:
- 可以在运行时加载和实例化类,而不需要在编译时确定类的确切类型。这对于插件架构和动态模块加载非常有用。
-
获取类的信息:
- 通过反射,可以获取类的名称、父类、接口、构造函数、方法和字段等信息,这对于调试和开发工具的实现非常重要。
-
动态方法调用:
- 可以在运行时调用对象的方法,而不需要在编译时知道方法名。这使得可以实现更加灵活的代码,比如根据用户输入或配置文件调用不同的方法。
-
访问和修改属性:
- 可以访问和修改对象的私有字段,例如进行测试时需要操作私有属性的情况。
-
实现通用库和框架:
- 许多Java框架(如Spring、Hibernate)使用反射来实现依赖注入、AOP(面向切面编程)、ORM(对象关系映射)等功能,使得框架能够对用户的应用程序进行灵活处理。
-
对象序列化与反序列化:
- 反射可以用于将对象转换为字节流或从字节流恢复对象,常用于对象的持久化和网络传输。
-
单元测试和Mock对象:
- 在单元测试中,可以使用反射来创建Mock对象,或访问被测试对象的私有方法和属性,进行更全面的测试。
反射提供了灵活性和可扩展性,但使用时也要注意其性能开销和对程序安全性的影响。
反射相关的类
在Java中,反射相关的类主要集中在 java.lang.reflect
包中,以下是一些常用的反射相关类:
-
Class:
- 代表一个类或接口的对象。可以用它来获取类的信息,包括类的名称、父类、实现的接口、字段、方法和构造方法等。
-
Method:
- 表示类中的某个方法。可以通过
Method
类调用该方法,获取方法的参数类型、返回值类型等信息。
- 表示类中的某个方法。可以通过
-
Field:
- 表示类中的某个字段(属性)。可以用它来获取字段的类型、访问修饰符,并可以通过反射访问或修改字段的值。
-
Constructor:
- 表示类的构造函数。可以通过
Constructor
类创建新的对象实例,并获取构造函数的参数类型、修饰符等信息。
- 表示类的构造函数。可以通过
-
Array:
- 提供了对数组的静态方法,可以动态地创建和访问数组。
-
AccessibleObject:
- 是
Field
、Method
和Constructor
的父类,包含了一个用于设置访问权限的方法setAccessible(boolean flag)
,可以通过它来访问私有成员。
- 是
-
InvocationTargetException:
- 当通过反射调用方法时,如果被调用的方法抛出异常,将会封装在这个异常中。
这些类提供了强大的能力,使得开发者能够在运行时动态地操作类和对象,从而实现灵活和可扩展的代码设计。在使用反射时,需要注意性能开销和安全性问题。
反射的一些相关类的方法
1. Class 类的方法
getName()
:返回类的完全限定名(包括包名)。getSuperclass()
:返回此 Class 对象所表示的类的父类的 Class 对象。getInterfaces()
:返回一个 Class 对象数组,表示所实现的接口。getDeclaredMethods()
:返回一个 Method 对象数组,表示此类声明的所有方法(包括私有方法)。getDeclaredFields()
:返回一个 Field 对象数组,表示此类声明的所有字段(包括私有字段)。getDeclaredConstructors()
:返回一个 Constructor 对象数组,表示此类声明的所有构造函数。
2. Method 类的方法
getName()
:返回方法的名称。getReturnType()
:返回方法的返回类型。getParameterTypes()
:返回一个 Class 对象数组,表示方法的参数类型。invoke(Object obj, Object... args)
:在指定对象上调用此 Method 对象表示的原始方法。setAccessible(boolean flag)
:设置此方法是否可以通过反射访问(包括私有方法)。
3. Field 类的方法
getName()
:返回字段的名称。getType()
:返回字段的类型(Class 对象)。get(Object obj)
:返回指定对象上此 Field 对象表示的字段的值。set(Object obj, Object value)
:为指定对象上此 Field 对象表示的字段设置值。setAccessible(boolean flag)
:设置此字段是否可以通过反射访问(包括私有字段)。
4. Constructor 类的方法
getName()
:返回构造函数的名称。getParameterTypes()
:返回一个 Class 对象数组,表示构造函数的参数类型。newInstance(Object... initargs)
:用构造函数创建新对象实例。
5. Array 类的方法
newInstance(Class<?> componentType, int... dimensions)
:创建一个指定组件类型和维度的新数组。get(Object array, int index)
:返回数组中指定索引处的值。set(Object array, int index, Object value)
:设置数组中指定索引处的值。
6. AccessibleObject 类的方法
setAccessible(boolean flag)
:设置此对象是否可被反射访问(如私有成员)。
这些方法使得Java反射能够处理类和对象的多种操作,增强了程序的灵活性和动态性。在使用时,请注意性能和安全性。
反射的使用
下面是一个简单的示例,演示如何使用反射来获取一个类的信息,并调用其方法。
假设我们有一个简单的类 Person
,包含一些属性和一个方法:
// Person.java
public class Person {private String name;private int age;public Person(String name, int age) {this.name = name;this.age = age;}public void introduce() {System.out.println("Hello, my name is " + name + " and I am " + age + " years old.");}// Getter和Setter方法public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}
}
以下是使用反射来访问 Person
类的代码:
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Field;public class ReflectionExample {public static void main(String[] args) {try {// 获取Person类的Class对象Class<?> personClass = Class.forName("Person");// 获取构造函数并创建实例Constructor<?> constructor = personClass.getConstructor(String.class, int.class);Object personInstance = constructor.newInstance("Alice", 30);// 获取并调用introduce方法Method introduceMethod = personClass.getMethod("introduce");introduceMethod.invoke(personInstance);// 获取并修改私有字段nameField nameField = personClass.getDeclaredField("name");nameField.setAccessible(true); // 允许访问私有字段nameField.set(personInstance, "Bob"); // 修改字段值// 再次调用introduce方法introduceMethod.invoke(personInstance);} catch (Exception e) {e.printStackTrace();}}
}
代码解释:
- 使用
Class.forName
获取Person
类的Class
对象。 - 通过
getConstructor
方法获取带有参数的构造函数,并使用newInstance
方法创建Person
类的一个实例。 - 使用
getMethod
获取introduce
方法,并通过invoke
调用该方法。 - 使用
getDeclaredField
获取私有字段name
,并通过setAccessible(true)
允许访问私有字段,接着修改它的值。 - 再次调用
introduce
方法,输出修改后的结果。
这个示例展示了如何通过反射访问和操作类的属性和方法。
反射优点和缺点
优点:
- 1. 对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法
- 2. 增加程序的灵活性和扩展性,降低耦合性,提高自适应能力
- 3. 反射已经运用在了很多流行框架如:Struts、Hibernate、Spring 等等。
缺点:
- 1.使用反射会有效率问题。会导致程序效率降低。具体参考这里:大家都说 Java 反射效率低,你知道原因在哪里么_慕课手记
- 2. 反射技术绕过了源代码的技术,因而会带来维护问题。反射代码比相应的直接代码更复杂
相关文章:
了解Java中的反射,带你如何使用反射
反射的定义 反射(Reflection)是Java的一种强大机制,它允许程序在运行时动态地查询和操作类的属性和方法。通过反射,Java程序可以获取类的信息,比如类的名称、方法、字段,以及可以动态地创建对象、调用方法…...

【c++】基础知识——快速入门c++
🌟🌟作者主页:ephemerals__ 🌟🌟所属专栏:C 目录 前言 一、手搓一个Hello World 二、命名空间namespace 1.命名空间的定义 2.命名空间的使用 3.命名空间补充知识 三、c中的输入和输出 四、缺省参…...

AI学习记录 - 自注意力机制的计算流程图
过段时间解释一下,为啥这样子计算,研究这个自注意力花了不少时间,网上很多讲概念,但是没有具体的流程图和计算方式总结…...
JavaScript快速入门,满满干货总结,快速掌握JS语法,DOM,BOM,事件
目录 一. JavaScript、HTML、CSS简介 1.1 HTML简介和举例说明 1.2 CSS简介和举例说明 1.3 JavaScript 简介和举例说明 二. JavaScript 基本语法 2.1 变量类型和定义方式 2.2 逻辑运算符,比较运算符 2.3 流程控制,if,if...else...&…...

【C++】C++入门基础【类与对象】
目录 1.类 1.1类的定义 1.2struct 与 class对比 2.访问限定符 3. 类域 4.实例化 5.存储大小----内存对齐 6.this指针 1.类 1.1类的定义 class作为类的关键字,后面跟的是类的名字,如Stack,{}中的为类的主体,类定义结束时…...
Qt | QScatterSeries 散点图
点击上方"蓝字"关注我们 01、QScatterSeries QScatterSeries 的类,它将代表散点图中的一个系列。这个类将包含数据点、颜色和样式等属性,以及用于绘制散点图的方法。 02、main.cpp #include <QtWidgets/QApplication>#include <QtWidgets/QMainWindow…...

无缝协作的艺术:Codigger 视频会议(Meeting)的用户体验
在当今数字化的时代,远程协作已经成为工作和学习中不可或缺的一部分。然而,远程协作也面临着诸多挑战,如沟通不畅、信息同步不及时、协作工具的复杂性等。而 Codigger 视频会议(Meeting)作为一款创新的工具,…...

C基础练习(学生管理系统)
1.系统运行,打开如下界面。列出系统帮助菜单(即命令菜单),提示输入命令 2.开始时还没有录入成绩,所以输入命令 L 也无法列出成绩。应提示“成绩表为空!请先使用命令 T 录入学生成绩。” 同理,当…...
网络安全抓包封包WEB
目录 1.抓包 1. 网络故障排除 应用 意义 2. 网络安全监控 应用 意义 3. 性能优化 应用 意义 4. 协议分析与开发 应用 意义 5. 数据分析与合规性审计 应用 意义 抓包工具 总结 2.抓包的应用对象 1. 网络设备 路由器和交换机 防火墙和入侵检测系统ÿ…...

Spring Boot - 在Spring Boot中实现灵活的API版本控制(上)
文章目录 为什么需要多版本管理?在Spring Boot中实现多版本API的常用方法1. URL路径中包含版本号2. 请求头中包含版本号3. 自定义注解和拦截器 注意事项 为什么需要多版本管理? API接口的多版本管理在我们日常的开发中很重要,特别是当API需要…...

普中51单片机:DS18B20温度传感器操作指南(十三)
文章目录 引言电路图引脚讲解初始化时序写时序读时序温度变换温度读取完整代码 引言 DS18B20是一款单总线接口的数字温度传感器,仅需一个IO口即可实现数据通信。这里只对如何简单操作开发板的DS1802进行讲解,关于DS18B20温度传感器的详细操作原理&#…...

【网络】网络的发展历程及其相关概念
1.什么是网络 计算机网络是指将一群具有独立功能的计算机通过通信设备以及传输媒体被互联起来的,在通信软件的支持下,实现计算机间资源共享、信息交换或协同工作的系统。计算机网络是计算机技术与通信技术紧密结合的产物,两者的迅速发展渗透形…...

鸿蒙HarmonyOS开发:如何使用第三方库,加速应用开发
文章目录 一、如何安装 ohpm-cli二、如何安装三方库1、在 oh-package.json5 文件中声明三方库,以 ohos/crypto-js 为例:2、安装指定名称 pacakge_name 的三方库,执行以下命令,将自动在当前目录下的 oh-package.json5 文件中自动添…...
C++的标准模板库简单介绍
C的标准模板库(STL, Standard Template Library)是一个强大的工具,旨在提供高效和灵活的数据结构和算法。STL的设计目的是使C程序更加通用和可重用。以下是对STL的详细介绍: 1. STL的组成部分 STL主要由以下几部分组成ÿ…...

安卓常用控件ListView
文章目录 ListView的常用属性ListView的常用APIListView的简单使用 ListView是一个列表样式的 ViewGroup,将若干 item 按行排列。它是一个很基本的控件也是 Android 中最重要的控件之一。它可以实现多个 View 的垂直排列并支持滚动显示效果。 ListView的常用属性 常…...

优秀的行为验证码的应用场景与行业案例
应用场景 登录注册 : 验证码适用于App、Web及小程序等用户注册场景,可以抵御自动机恶意注册,垃圾注册、抵御撞库登录、暴力破解、验证账号敏感信息的修改,同时可以有效阻止撞库攻击,从源头进行防护,保障正…...

《程序猿入职必会(10) · SpringBoot3 整合 MyBatis-Plus》
📢 大家好,我是 【战神刘玉栋】,有10多年的研发经验,致力于前后端技术栈的知识沉淀和传播。 💗 🌻 CSDN入驻不久,希望大家多多支持,后续会继续提升文章质量,绝不滥竽充数…...

计算机网络408考研 2018
1 计算机网络408考研2018年真题解析_哔哩哔哩_bilibili...

(亲测有效)SpringBoot+Vue项目云服务器部署(宝塔)
目录 一、准备工作 1、购买云服务器 2、获取面板地址 二、jdk和数据库 1、安装环境 2、安装Java环境jdk 3、添加数据库 三、前端部署 1、修改后台服务所在源 2、vue build 2、创建站点 四、后端部署 1、修改application.yml 2、idea打包 3、运行jar包 方式一&a…...

健康管理系统
目录 第1章 系统概述 第2章 可行性研究 2.1 项目背景及意义 2.2 可行性研究 第3章 需求分析 3.1 功能性需求 3.2 非功能性需求 3.2.1 性能需求 第4章 总体设计 4.1 技术架构 4.2功能模块设计 第5章 详细设计 5.1 主页 5.2 写剧本杀 5.3 剧本杀分类管理 5.4 个人…...

手游刚开服就被攻击怎么办?如何防御DDoS?
开服初期是手游最脆弱的阶段,极易成为DDoS攻击的目标。一旦遭遇攻击,可能导致服务器瘫痪、玩家流失,甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案,帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...

树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法
树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作,无需更改相机配置。但是,一…...
AtCoder 第409场初级竞赛 A~E题解
A Conflict 【题目链接】 原题链接:A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串,只有在同时为 o 时输出 Yes 并结束程序,否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...

STM32标准库-DMA直接存储器存取
文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA(Direct Memory Access)直接存储器存取 DMA可以提供外设…...
OpenLayers 分屏对比(地图联动)
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能,和卷帘图层不一样的是,分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...

Redis数据倾斜问题解决
Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中,部分节点存储的数据量或访问量远高于其他节点,导致这些节点负载过高,影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...

使用 SymPy 进行向量和矩阵的高级操作
在科学计算和工程领域,向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能,能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作,并通过具体…...

C++使用 new 来创建动态数组
问题: 不能使用变量定义数组大小 原因: 这是因为数组在内存中是连续存储的,编译器需要在编译阶段就确定数组的大小,以便正确地分配内存空间。如果允许使用变量来定义数组的大小,那么编译器就无法在编译时确定数组的大…...

Kafka入门-生产者
生产者 生产者发送流程: 延迟时间为0ms时,也就意味着每当有数据就会直接发送 异步发送API 异步发送和同步发送的不同在于:异步发送不需要等待结果,同步发送必须等待结果才能进行下一步发送。 普通异步发送 首先导入所需的k…...

【Redis】笔记|第8节|大厂高并发缓存架构实战与优化
缓存架构 代码结构 代码详情 功能点: 多级缓存,先查本地缓存,再查Redis,最后才查数据库热点数据重建逻辑使用分布式锁,二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...