2023.12.12 关于 Java 反射详解
目录
基本概念
定义
用途
反射相关的类
反射基本原理
Class 类中的相关方法
常用获得类相关的方法
常用获得类中属性相关的方法
常用获得类中构造器相关的方法
常用获得类中方法相关的方法
实例理解
反射优缺点
基本概念
定义
- Java 的反射(reflection)机制是一种强大功能,它可以让我们在运行时动态地获取和操作 类 或 对象 的信息
实例理解
- 我们可以通过反射机制来创建一个类的对象,而不需要使用 new 关键字
- 我们也可以通过反射机制来访问或修改一个对象的私有属性或方法,而不需要遵循封装原则
- 我们还可以通过反射机制来调用一个对象的任意方法,而不需要知道它的参数类型或返回值类型
用途
典型用途一:
- 在开发第三方应用时,我们可能会遇到一些类的成员变量、方法或属性是私有的,或者只对系统应用开放,这就意味着我们不能直接访问这些成员或方法
- 这时我们便可以在运行时 通过 Java 的反射机制 来动态地访问和操作类的内部成员,包括私有成员和方法
典型用途二:
- 反射在开发通用框架 Spring 中起着重要的作用
- 在Spring 框架中,所有类(Bean)都由 Spring 容器进行管理,这些 Bean 可以通过 XML 配置或注解来配置
- 当我们从容器中获取Bean 以进行依赖注入时,容器会读取配置信息,这些配置信息包含了类的信息,比如类的名称、属性、方法等
- Spring根据这些信息 动态地创建这些类的实例,这个过程就是所谓的 依赖注入,该过程中,反射起到了关键作用
- Spring 使用反射来动态地创建类的实例,调用方法,以及设置属性值
反射相关的类
反射基本原理
- Java 的反射机制是基于 java.lang.Class 类实现的
- 当我们编译一个 Java 文件时,会生成一个 .class 文件
- 当 JVM 加载这个 .class 文件时,会将其解析为一个 java.lang.Class 类的对象
- 在程序运行时,每个 Java 文件都会被 JVM 解析为一个 Class 类的实例
- 这个 Class 类的实例包含了该 Java 文件中所定义类的所有信息,包括类的名称、属性、方法等
- 我们可以通过 Java 的反射机制来操作这个 Class 类的实例
- 具体来说,我们可以使用反射来获取类的属性和方法,甚至可以添加或修改类的属性和方法
- 这使得我们可以在运行时动态地操作类,使其成为一个 动态的类
类名 用途 Class 类 代表类的实体,在运行的 Java 应用程序中表示类和接口 Field 类 代表类的成员变量、类的属性 Method 类 代表类的方法 Constructor 类 代表类的构造方法
Class 类中的相关方法
常用获得类相关的方法
方法 用途 getClassLoader() 获得类的加载器 getDeclaredClasses() 返回一个数组,数组中包含该类中所有类和接口类的对象(包括私有的) forName(String className) 根据类名返回类的对象 newInstance() 创建类的实例 getName() 获得类的完整路径名字 常用获得类中属性相关的方法
方法 用途 getField(String name) 获得某个公有的属性对象 getFields() 获得所有公有的属性对象 getDeclaredField(String name) 获得某个属性对象 getDeclaredFields() 获得所有属性对象 常用获得类中构造器相关的方法
方法 用途 getConstructor(Class <?> parameterTypes) 获得该类中与参数类型匹配的公有构造方法 getConstructors() 获得该类的所有公有构造方法 getDeclaredConstructor(Class <?> parameterTypes) 获得该类中与参数类型匹配的构造方法 getDeclaredConstructors() 获得该类所有构造方法 常用获得类中方法相关的方法
方法 用途 getMethod(String name, Class <?> parameterTypes) 获得该类某个公有的方法 getMethods() 获得该类所有公有的方法 getDeclaredMethod(String name, Class <?> parameterTypes) 获得该类某个方法 getDeclaredMethods() 获得该类所有方法
实例理解
- 此处我们先创建一个 Student 类
class Student{//私有属性nameprivate String name = "master";//公有属性agepublic int age = 18;//不带参数的构造方法public Student(){System.out.println("Student()");}private Student(String name,int age) {this.name = name;this.age = age;System.out.println("Student(String,name)");}private void eat(){System.out.println("make hamburger!");}public void sleep(){System.out.println("go to bed!");}private void function(String str) {System.out.println(str);}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';} }
- 此处介绍三种方式来获取 Student 的 Class 对象
public class Demo1 {public static void main(String[] args) { // 有三种方式可以获取 Class 对象Student student1 = new Student(); // 1、通过对象的 getClass() 方法Class<?> c1 = student1.getClass(); // 2、通过类名 .class 获取Class<?> c2 = Student.class; // 3、通过调用 Class.forName() 方法获取了 Student 类的 Class 对象 // Class.forName() 方法需要一个类的全限定名(包括 包名和类名) 作为参数 // 此处的 ? 是一个通配符,用于表示未知类型 // 当我们声明一个泛型变量时,如果我们不确定或不关心实际的类型参数,我们可以使用 ? 来表示Class<?> c3 = null;try {c3 = Class.forName("Student");} catch (ClassNotFoundException e) {throw new RuntimeException(e);} // 此处证明通过上述三种方式所获取的 Class 对象 都是同一个System.out.println((c1.equals(c2) && c1.equals(c3) && c2.equals(c3)) ? "true" : "false");} }
- 此处我们通过反射机制创建一个对象
import java.lang.reflect.InvocationTargetException;public class ReflectClassDemo {// 通过反射创建一个对象public static void reflectNewInstance() throws InstantiationException, IllegalAccessException, ClassNotFoundException {Class<?> c3 = Class.forName("Student"); // 通过调用 Class 类的 newInstance() 方法来创建一个 c3 对应类的新实例 // newInstance() 方法调用的是这个类的无参构造函数 // 如果这个类没有无参构造函数,或者无参构造函数是私有的,那么 newInstance 会抛出一个异常 // 因为 newInstance() 方法返回的类型为 Object 类 所以需要类型转换,此处转换为 Student 类Student student = (Student) c3.newInstance();System.out.println(student);}public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException, NoSuchFieldException {reflectNewInstance();} }运行结果:
- 此处我们通过反射机制获取私有的构造方法
import java.lang.reflect.Constructor;public class ReflectClassDemo {// 通过反射获取私有的构造方法public static void reflectPrivateConstructor() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {Class<?> c3 = Class.forName("Student");Constructor<?> constructor = c3.getDeclaredConstructor(String.class,int.class); // 注意只要是涉及到 private 都要使用 setAccessible(true) 来打开权限,此处的构造方法为私有的constructor.setAccessible(true); // 此处利用构造方法 修改年龄和性别Student student = (Student)constructor.newInstance("xiaolin",20);System.out.println(student);}public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException, NoSuchFieldException {reflectPrivateConstructor();} }运行结果:
- 此处我们通过反射机制获取私有属性
import java.lang.reflect.Field;public class ReflectClassDemo {// 通过反射获取私有属性public static void reflectPrivateField() throws ClassNotFoundException, NoSuchFieldException, InstantiationException, IllegalAccessException {Class<?> c3 = Class.forName("Student");Field field = c3.getDeclaredField("name"); // 注意只要是涉及到 private 都要使用 setAccessible(true) 来打开权限,此处的 name 属性是私有的field.setAccessible(true);Student student = (Student) c3.newInstance(); // 此处修改私有属性field.set(student,"haoran");System.out.println(student);}public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException, NoSuchFieldException {reflectPrivateField();} }运行结果:
- 此处我们通过反射机制获取私有方法
import java.lang.reflect.Method;public class ReflectClassDemo {// 通过反射获取私有方法public static void reflectPrivateMethod() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {Class<?> c3 = Class.forName("Student");Method method1 = c3.getDeclaredMethod("function", String.class);Method method2 = c3.getDeclaredMethod("sleep"); // 注意只要是涉及到 private 都要使用 setAccessible(true) 来打开权限,此处的 function 方法是私有的method1.setAccessible(true);Student student = (Student) c3.newInstance(); // 此处给 function 方法传参method1.invoke(student,"此处利用反射机制给 function 方法传个字符串参数"); // 此处调用 sleep 方法,该方法为 public 无需额外打开权限,直接调用即可method2.invoke(student);}public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException, NoSuchFieldException {reflectPrivateMethod();} }运行结果:
反射优缺点
优点
- 对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个类都能调用它的任意一个方法
- 增加程序的灵活性和扩展性,降低耦合性,提高自适应性
- 反射已经运用在很多流行框架,典型代表为 Spring
缺点
- 使用反射会有效率问题,会导致程序效率降低
- 反射技术绕过了源代码的技术,因而会带来维护问题
- 反射代码比相应的直接代码更复杂
总结:
- 虽然反射非常强大,但也需要谨慎使用
- 我们需要在反射带来的灵活性和可扩展性与其带来的性能开销、维护问题和代码复杂性之间找到一个平衡
- 某些情况下,比如开发通用的框架,使用反射式非常有价值的
- 但在其他情况下,我们可能更倾向于使用更简单、更直接的代码
相关文章:
2023.12.12 关于 Java 反射详解
目录 基本概念 定义 用途 反射相关的类 反射基本原理 Class 类中的相关方法 常用获得类相关的方法 常用获得类中属性相关的方法 常用获得类中构造器相关的方法 常用获得类中方法相关的方法 实例理解 反射优缺点 基本概念 定义 Java 的反射(reflection&a…...
【Qt QML入门】Image
Image类型显示一个图像。 使用source属性将图像的源指定为URL。图像可以以Qt支持的任何标准图像格式提供,包括位图格式,如PNG和JPEG,以及矢量图形格式,如SVG。 如果没有指定宽度和高度属性,图像将自动使用加载图像的大…...
Spark编程入门
1.8 Spark编程入门 1.8.1 通过IDEA创建Spark工程 ps:工程创建之前步骤省略,在scala中已经讲解,直接默认是创建好工程的 导入Pom文件依赖 <!-- 声明公有的属性 --><properties><maven.compiler.source>1.8</maven.compiler.source><maven.compiler…...
JVM 内存分析工具 Memory Analyzer Tool(MAT)的深度讲解
目录 一. 前言 二. MAT 使用场景及主要解决问题 三. MAT 基础概念 3.1. Heap Dump 3.2. Shallow Heap 3.3. Retained Set 3.4. Retained Heap 3.5. Dominator Tree 3.6. OQL 3.7. references 四. MAT 功能概述 4.1. 内存分布 4.2. 对象间依赖 4.3. 对象状态 4.4…...
浅谈 USB Bulk 深入浅出 (3) - USB Bulk 装置传输的注意事项
来源:大大通 作者:冷氣團 1 USB Bulk 是什么 USB 是即插即用使用差动信号的装置界面,是以 端点 ( Endpoint ),做为传输装置的输出入端,透过不同的端点 ( Endpoint ) 和模式,来进行与装置的沟通ÿ…...
c语言结构体调用格式与对齐
1.声明形式: struct 结构体名字 { 结构体成员 }结构体变量名; 2.赋值方法 3.结构体对齐: 1.起始偏移量:默认结构体第一个元素对齐0起始偏移量,第一个元素占一个字节,此时偏移量为1. 2.标准数ÿ…...
服务器常用命令介绍和负载监控的工具插件推荐
先赞后看,养成习惯!!!❤️ ❤️ ❤️ 码字不易,如果喜欢可以关注我哦! 如果本篇文章对你有所启发,欢迎访问我的个人博客 命令 服务器相关 5个常用命令 top Top命令不仅显示了当前内核服务的…...
linux 防火墙systemctl (个人笔记)
查看 systemctl status firewalld 开启 systemctl start firewalld 关闭 systemctl stop firewalld.service 查看所有 firewall-cmd --zonepublic --list-ports 开放端口:// --permanent 永久生效,没有此参数重启后失效 firewall-cmd --zonepublic --add-port9527/…...
处理器中store指令的处理
对于向存储器中保存数据的store指令来说,它在顺利离开流水线之前是不允许改变处理器状态的,只有等到它退休(retire)的时候,才允许将它携带的数据写到D-Cache中在此之前,store指令即使计算完毕,也会将结果暂存在一个缓存中…...
杨辉三角形-第11届蓝桥杯选拔赛Python真题精选
[导读]:超平老师的Scratch蓝桥杯真题解读系列在推出之后,受到了广大老师和家长的好评,非常感谢各位的认可和厚爱。作为回馈,超平老师计划推出《Python蓝桥杯真题解析100讲》,这是解读系列的第17讲。 杨辉三角形&#…...
我们一起做过的SPA——Nuxt.js介绍
Nuxt.js 1 我们一起做过的SPA SPA(single page web application)单页 Web 应用,Web 不再是一张张页面,而是一个整体的应用,一个由路由系统、数据系统、页面(组件)系统等等,组成的应…...
java导出word使用模版与自定义联合出击解决复杂表格!
1. 看一下需要导出什么样子的表格 如图所示,这里的所有数据行都是动态的,需要根据查询出来的数据循环展示。 如果只是这样的话,使用freemarker应该都可以搞定,但是他一列中内容相同的单元格,需要合并。 这对于表格样式…...
GO设计模式——9、过滤器模式(结构型)
目录 过滤器模式(Filter/Criteria Pattern) 代码实现 过滤器模式(Filter/Criteria Pattern) 过滤器模式(Filter Pattern)或标准模式(Criteria Pattern)是一种设计模式,…...
fastadmin 导出
php 接收数据 set_time_limit(0);ini_set(memory_limit, -1);$ids $this->request->post(ids);$filter $this->request->post(filter);$op $this->request->post(op);$search $this->request->post(search);$whereIds $ids all ? 11 : [id >…...
六、CM4树莓派USBRS转485串口通讯
一、串行通讯接口 串行通讯接口简称串口(UART) 采用串行通信方式的扩展接口,数据位一位一位的按照顺序传送 优点:通信线路简单,只要一对传输线就可以实现双向通信能够大大降低成本,适合远距离通信。 缺点…...
c++知识总结
一 细碎知识 1.27 # 1.27.1 # pragma once 参考 C++学习笔记之pragma once的理解_pragma once什么意思-CSDN博客https://blog.csdn.net/lynnlee_36/article/details/105322937作用 保证只被编译一次,和#ifndef,#define,#endif功能相同 1.27.2 #if defined(__cplusplus…...
python-爬取壁纸
代理池的,防止IP 被封 找到图片真实地址 现在看到的只是图片的预览地址 (previews) 1.检查: 2.鼠标变为箭头时查看网页源代码 关于怎样在源代码中找到图片的真实地址 ??? 为什么在源代码界面 ctrl f 时候搜索的是 .png ??? 首先图片地址是以 .j…...
第31期 | GPTSecurity周报
GPTSecurity是一个涵盖了前沿学术研究和实践经验分享的社区,集成了生成预训练Transformer(GPT)、人工智能生成内容(AIGC)以及大型语言模型(LLM)等安全领域应用的知识。在这里,您可以…...
湖仓一体架构理论与实践汇总
湖仓一体架构理论与实践汇总 软件研发本质上属于“手工业”。软件研发在很大程度上还是依赖于个人的能力。当软件规模较小时,依赖“手工业”可以解决问题,但是当软件规模大了之后再依赖“手工业”就不行了。 软件的复杂度包含两个层面:软件…...
Redission从入门到入门
1. Redisson简介 Redisson 是一个在 Java 环境中使用的 Redis 客户端库。它提供了丰富的功能,使得在 Java 应用中与 Redis 交互变得更加简单和高效。Redisson 不仅提供了基本的 Redis 操作,还提供了许多高级功能,使其成为在 Java 项目中实现…...
云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?
大家好,欢迎来到《云原生核心技术》系列的第七篇! 在上一篇,我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在,我们就像一个拥有了一块崭新数字土地的农场主,是时…...
大话软工笔记—需求分析概述
需求分析,就是要对需求调研收集到的资料信息逐个地进行拆分、研究,从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要,后续设计的依据主要来自于需求分析的成果,包括: 项目的目的…...
css实现圆环展示百分比,根据值动态展示所占比例
代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...
centos 7 部署awstats 网站访问检测
一、基础环境准备(两种安装方式都要做) bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats࿰…...
Nuxt.js 中的路由配置详解
Nuxt.js 通过其内置的路由系统简化了应用的路由配置,使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...
【Java_EE】Spring MVC
目录 Spring Web MVC 编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 编辑参数重命名 RequestParam 编辑编辑传递集合 RequestParam 传递JSON数据 编辑RequestBody …...
【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)
升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点,但无自动故障转移能力,Master宕机后需人工切换,期间消息可能无法读取。Slave仅存储数据,无法主动升级为Master响应请求ÿ…...
代码随想录刷题day30
1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...
安宝特案例丨Vuzix AR智能眼镜集成专业软件,助力卢森堡医院药房转型,赢得辉瑞创新奖
在Vuzix M400 AR智能眼镜的助力下,卢森堡罗伯特舒曼医院(the Robert Schuman Hospitals, HRS)凭借在无菌制剂生产流程中引入增强现实技术(AR)创新项目,荣获了2024年6月7日由卢森堡医院药剂师协会࿰…...
CRMEB 中 PHP 短信扩展开发:涵盖一号通、阿里云、腾讯云、创蓝
目前已有一号通短信、阿里云短信、腾讯云短信扩展 扩展入口文件 文件目录 crmeb\services\sms\Sms.php 默认驱动类型为:一号通 namespace crmeb\services\sms;use crmeb\basic\BaseManager; use crmeb\services\AccessTokenServeService; use crmeb\services\sms\…...



