关于java的反射

❓❓❓反射是啥呀相信许多学java的同学非常困惑在学的时候,总是感觉懂了却又没懂或者直接忽略过去了,那么本文就带大家探讨一下什么是反射在java中以及它的机制和运用。

⭐️什么是反射:

首先我们知道一些知识:

维基百科的解释

在计算机学中,反射式编程(英语:reflective programming)或反射(英语:reflection),是指计算机程序在运行时(runtime)可以访问、检测和修改它本身状态或行为的一种能力.用比喻来说,反射就是程序在运行的时候能够“观察”并且修改自己的行为。
要注意术语“反射”和“内省”(type introspection)的关系。内省(或称“自省”)机制仅指程序在运行时对自身信息(称为元数据)的检测;反射机制不仅包括要能在运行时对程序自身信息进行检测,还要求程序能进一步根据这些信息改变程序状态或结构。

这个解释用在java就是通过jvm创建class示例进行操作反过来又能对对象进行访问和修改。反射(Reflection)是 Java 的一种特性,它可以让程序在运行时获取自身的信息,并且动态地操作类或对象的属性、方法和构造器等。通过反射功能,可以让我们在不知道具体类名的情况下,依然能够实例化对象,调用方法以及设置属性。
首先知道一个加载过程
img
在这里插入图片描述

Java语言的编译过程主要包括以下几个步骤:

词法分析:
词法分析器(Lexer)读取源代码文件,将源代码中的字符序列转换为记号(Token)序列。这些记号是编译器进一步处理的基本单元。
语法分析:
语法分析器(Parser)根据Java语言的语法规则,将词法分析器输出的记号序列组织成语法树(Abstract Syntax Tree, AST)。语法树表示了源代码中的程序结构。
语义分析:
语义分析器检查语法树是否满足语义规则,比如变量是否已经声明、类型是否匹配、表达式是否有意义等。这个阶段还会进行一些类型推断和转换。
字节码生成:
编译器将经过语义分析后的语法树转换成字节码(Bytecode)。字节码是一种平台无关的中间代码,它可以在任何安装了Java虚拟机(JVM)的平台上运行。
具体来说,Java编译过程如下:
源代码到字节码:
使用javac命令或Java编译器API将.java源文件编译成.class字节码文件。这一步包含了上述的词法分析、语法分析、语义分析和字节码生成。
字节码验证:
当.class文件被加载到JVM时,字节码验证器会检查字节码文件,确保其遵循Java语言规范,没有安全问题,比如确保不会发生数组越界、栈溢出等。
类加载:
类加载器(ClassLoader)负责将.class文件加载到JVM中,并为字节码分配内存,将其转换为运行时数据结构。
运行时优化:
JVM可能会对字节码进行即时编译(Just-In-Time, JIT)优化,将字节码转换成本地机器码以提高执行效率。
执行:
最终,在JVM上执行这些字节码,程序开始运行。
这个过程确保了Java语言的“一次编写,到处运行”的特性,因为编译生成的字节码可以在任何有JVM的平台上执行。

然后我们正式开始:
反射之中包含了一个「反」字,所以想要解释反射就必须先从「正」开始解释。

一般情况下,我们使用某个类时必定知道它是什么类,是用来做什么的。于是我们直接对这个类进行实例化,之后使用这个类对象进行操作。

Apple apple = new Apple(); //直接初始化,「正射」
apple.setPrice(4);

上面这样子进行类对象的初始化,我们可以理解为「正」。

而反射则是一开始并不知道我要初始化的类对象是什么,自然也无法使用 new 关键字来创建对象了。

这时候,我们使用 JDK 提供的反射 API 进行反射调用:

Class clz = Class.forName("com.muggle.reflect.Apple");
Method method = clz.getMethod("setPrice", int.class);
Constructor constructor = clz.getConstructor();
Object object = constructor.newInstance();
method.invoke(object, 4);

上面两段代码的执行结果,其实是完全一样的。但是其思路完全不一样,第一段代码在未运行时就已经确定了要运行的类(Apple),而第二段代码则是在运行时通过字符串值才得知要运行的类(com.chenshuyi.reflect.Apple)。

所以说什么是反射?

反射就是在运行时才知道要操作的类是什么,并且可以在运行时获取类的完整构造,并调用对应的方法。
(1)Java反射机制的核心是在程序运行时动态加载类并获取类的详细信息,从而操作类或对象的属性和方法。本质是JVM得到class对象之后,再通过class对象进行反编译,从而获取对象的各种信息。

(2)Java属于先编译再运行的语言,程序中对象的类型在编译期就确定下来了,而当程序在运行时可能需要动态加载某些类,这些类因为之前用不到,所以没有被加载到JVM。通过反射,可以在运行时动态地创建对象并调用其属性,不需要提前在编译期知道运行的对象是谁。

⭐️获取Class对象的三种方式

package fanshe;
/*** 获取Class对象的三种方式* 1 Object ——> getClass();* 2 任何数据类型(包括基本数据类型)都有一个“静态”的class属性* 3 通过Class类的静态方法:forName(String  className)(常用)**/
public class Fanshe {public static void main(String[] args) {//第一种方式获取Class对象  Student stu1 = new Student();//这一new 产生一个Student对象,一个Class对象。Class stuClass = stu1.getClass();//获取Class对象System.out.println(stuClass.getName());//第二种方式获取Class对象Class stuClass2 = Student.class;System.out.println(stuClass == stuClass2);//判断第一种方式获取的Class对象和第二种方式获取的是否是同一个//第三种方式获取Class对象try {Class stuClass3 = Class.forName("fanshe.Student");//注意此字符串必须是真实路径,就是带包名的类路径,包名.类名System.out.println(stuClass3 == stuClass2);//判断三种方式是否获取的是同一个Class对象} catch (ClassNotFoundException e) {e.printStackTrace();}}
}

⭐️反射的运用

框架:半成品软件。可以在框架的基础上进行软件开发,简化编码
反射:将类的各个组成部分封装为其他对象,这就是反射机制
​ 好处:
​ 可以在程序运行过程中,操作这些对象。
​ 可以解耦,提高程序的可扩展性。
像咱们平时大部分时候都是在写业务代码,很少会接触到直接使用反射机制的场景。但是,这并不代表反射没有用。相反,正是因为反射,你才能这么轻松地使用各种框架。像 Spring/Spring Boot、MyBatis 等等框架中都大量使用了反射机制。这些框架中也大量使用了动态代理,而动态代理的实现也依赖反射。比如下面是通过 JDK 实现动态代理的示例代码,其中就使用了反射类 Method 来调用指定的方法。

public class DebugInvocationHandler implements InvocationHandler {/*** 代理类中的真实对象*/private final Object target;public DebugInvocationHandler(Object target) {this.target = target;}public Object invoke(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException {System.out.println("before method " + method.getName());Object result = method.invoke(target, args);System.out.println("after method " + method.getName());return result;}
}

另外,像 Java 中的一大利器 注解 的实现也用到了反射。为什么你使用 Spring 的时候 ,一个@Component注解就声明了一个类为 Spring Bean 呢?为什么你通过一个 @Value注解就读取到配置文件中的值呢?究竟是怎么起作用的呢?这些都是因为你可以基于反射分析类,然后获取到类/属性/方法/方法的参数上的注解。你获取到注解之后,就可以做进一步的处理。谈谈反射机制的优缺点优点:可以让咱们的代码更加灵活、为各种框架提供开箱即用的功能提供了便利缺点:让我们在运行时有了分析操作类的能力,这同样也增加了安全问题。比如可以无视泛型参数的安全检查(泛型参数的安全检查发生在编译时)。
在使用 JDBC 连接数据库时使用 Class.forName()通过反射加载数据库的驱动程序,如果是mysql则传入mysql的驱动类,而如果是oracle则传入的参数就变成另一个了。

Spring 框架的 IOC(动态加载管理 Bean),Spring通过配置文件配置各种各样的bean,你需要用到哪些bean就配哪些,spring容器就会根据你的需求去动态加载,你的程序就能健壮地运行。

还有Spring AOP(动态代理)功能都和反射有关系。

除此之外还有很多框架:mybatis、dubbo、rocketmq等等都会用到反射机制。


参考

反射的作用
大白话说反射
javaguide
java非常重要的基础概念之一
反射

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/45667.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

springboot项目 导入 maven坐标 错误 Could not transfer artifact XXX

1.报错原因 当时导入的是 redis坐标 ,导入jar 包报错(当时是网速太慢了,一直卡着不动 就关了 idea 重新下载)结果报错 之前的redis 项目都可以的,网上找了一下 都没解决 2.解决办法 既然说不能传输, 就说…

有用的工具

一、appuploader Appuploader home -- A tool improve ios develop efficiency such as submit ipa to appstore and manage ios certificate这是一款p12证书查看的工具, 需要建立一个apple ID专用密码:Manage your Apple ID

redis其他类型和配置文件

很多博客只讲了五大基本类型,确实,是最常用的,而且百分之九十的程序员对于Redis只限于了解String这种最常用的。但是我个人认为,既然Redis官方提供了其他的数据类型,肯定是有相应的考量的,在某些特殊的业务…

C++相关概念和易错语法(22)(final、纯虚函数、继承多态难点)

1.final final在继承和多态中都可以使用,在继承中是指不想将自己被继承,在多态中是指不想该函数被重写,比较简单,下面是一些使用例子。 2.纯虚函数 当我们需要抽象一个类的时候,我们就需要用到纯虚函数。所谓抽象的类…

如何设计统计量及相关假设检验

一、如何设置H0和H1假设 谁做H0,谁做H1,在统计学的假设检验里是有约定俗成的规定的。即:status quo(默认/现状)是H0,而新观点或试图challenge现状的是H1。H1也叫research hypothesis,所以我们做…

【多个Python版本存在,使用pip+不同版本安装库时,windows弹出打开方式窗口的解决方法】

问题描述 电脑上存在python3.9,3.10,3.11,安装顺序也是先安装3.9,然后3.10,最后3.11,那么直接使用pip安装,会装在3.11的位置,经过搜索可以通过pip版本,比如pip3.9 insta…

如何在勒索软件攻击中幸存下来:最佳备份实践、勒索拦截方案

无论身处什么业务或行业,数据都是您业务的关键资产。没有针对数据进行安全可靠的备份保护,您将会受到许多“可能性”的威胁,无论数据丢失是由于在键盘上洒了饮料还是遭受到了勒索软件的攻击。 为了确保业务不被中断,企业数据不会…

Python: 初识Python

文章目录 1. Python的背景知识1.1 Python是咋来的?1.2 Python的特点1.3 Python能干啥?1.4 Python的缺点 2. 搭建Python环境2.1 安装Python2.2 安装PyCharm2.3 用pycharm编写python程序 1. Python的背景知识 1.1 Python是咋来的? 由Guido van Rossum于1989年圣诞节为打发无…

一个用于管理多个 Node.js 版本的安装和切换开源工具

大家好,今天给大家分享一个用于管理多个Node.js版本的工具 NVM(Node Version Manager),它允许开发者在同一台机器上安装和使用不同版本的Node.js,解决了版本兼容性问题,为开发者提供了极大的便利。 在开发环…

路网双线合并单线——ArcGISpro 解决方法

路网双线合并成单线是一个在地图制作、交通规划以及GIS分析中常见的需求。双线路网定义:具有不同流向、不同平面结构的道路。此外,车道数较多的道路(例如,双黄实线车道数大于4的道路)也可以视为双线路网,本…

iPhone 如何修改锁屏密码?修改密码的具体步骤总结

修改 iPhone 锁屏密码 当你还记得当前设置的锁屏密码时,想要修改密码就非常的简单了,只需要简单的点几下就可以重新设置新密码,下面是具体的操作步骤: 首先我们进入设置应用程序,然后找到“面容 ID 与密码”。 然后需…

(01)Unity使用在线AI大模型(使用百度千帆服务)

目录 一、概要 二、环境说明 三、申请百度千帆Key 四、使用千帆大模型 四、给大模型套壳 一、概要 在Unity中使用在线大模型分为两篇发布,此篇文档为在Python中使用千帆大模型,整体实现逻辑是:在Python中接入大模型—>发布为可传参的…

护眼台灯的功能作用有哪些?深挖台灯护眼是真的吗

随着现代生活方式的改变,孩子们面临着越来越多的视力挑战。在近视学生中,近10%为高度近视,且占比随年级升高而增长。幼儿园6岁儿童中有1.5%为高度近视,而高中阶段则达到了17.6%。为了守护孩子们的视力健康,在科技飞速发…

无符号数和有符号数的转换

1、有符号数转换成无符号数 1.1 例一 首先,我们需要清楚 C语言中负数是以补码的形式进行存储的。 示例:负数-1, (此处,假设是8位二进制表示) 对应正数的原码:0000 0001;取反&…

通俗易懂多图透彻讲解二叉树的遍历--前序, 中序和后序

二叉树的遍历是一个数据结构中经常会遇到的知识点, 具体又分为前序, 中序和后序三种. 什么是树? 先来理解一下什么是树, 从一个我们相对熟悉的家谱树(Family Tree)说起吧. 家族的根是爷爷, 然后生了两个娃, 大伯和你爸爸. 继续往下, 有堂哥堂姐, 还有你以及你妹, 等等. 一个…

简化流程,强化协作——揭秘可道云TeamOS文档审批的实用魅力

在团队协作的过程中,文档审批是确保信息安全和流程规范的重要环节。然而,传统的文档审批流程往往繁琐且僵化,难以满足团队快速响应和灵活协作的需求。 可道云teamOS的文档审批功能,以其独特的灵活性和便捷性,为团队带…

java——Junit单元测试

测试分类 黑盒测试:不输入代码,给输入值,看程序能够给出期望的值。 白盒测试:写代码,关注程序具体执行流程。 JUnit单元测试 一个测试框架,供java开发人员编写单元测试。 是程序员测试,即白…

PBT激光穿透率测量仪

在现代材料科学与工业制造领域,激光技术以其高精度、高效率和非接触性等特点,成为了不可或缺的测量与加工手段。其中,PBT(聚对苯二甲酸丁二醇酯)作为一种重要的热塑性工程塑料,因其优异的机械性能、耐热性和…

嵌入式全栈设计思路:STM32G4+ChibiOS+FreeRTOS+PID控制+PFC算法构建高效智能电源管理系统(附代码示例)

智能电源管理系统是一个基于STM32G4微控制器的高性能数字电源控制解决方案。本项目旨在设计一个功能全面、高效稳定的电源管理系统,可广泛应用于工业控制、新能源、通信设备等领域。 1.1 系统主要特点 高精度数字电源控制:利用STM32G4的高性能ADC和定时器,实现精确…

HTML5+CSS3小实例:纯CSS实现奥运五环

实例:纯CSS实现奥运五环 技术栈:HTML+CSS 效果: 源码: 【HTML】 <!DOCTYPE html> <html lang="zh-CN"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-sca…