当前位置:首页 > 科技  > 软件

Java 反射:让你更优雅的使用框架!

来源: 责编: 时间:2024-05-24 17:23:32 318观看
导读在 Java语言中,反射是一种强大而优秀的机制,通过反射,我们可以在运行时检查和修改类、接口、字段和方法的信息,甚至动态地创建对象、调用方法和访问私有成员。可以毫不夸张地说,没有反射,很多优秀的框架不复存在,没有这些优

在 Java语言中,反射是一种强大而优秀的机制,通过反射,我们可以在运行时检查和修改类、接口、字段和方法的信息,甚至动态地创建对象、调用方法和访问私有成员。cip28资讯网——每日最新资讯28at.com

可以毫不夸张地说,没有反射,很多优秀的框架不复存在,没有这些优秀的框架(比如Spring),Java可能会逊色很多,因此,这篇文章,我们一起来深入探讨Java反射以及其背后的原理。cip28资讯网——每日最新资讯28at.com

cip28资讯网——每日最新资讯28at.com

cip28资讯网——每日最新资讯28at.com

一、什么是反射

先看看 Oracle官方对java反射的说明:cip28资讯网——每日最新资讯28at.com

Reflection enables Java code to discover information about the fields, methods and constructors of loaded classes, and to use reflected fields, methods, and constructors to operate on their underlying counterparts, within security restrictions. The API accommodates applications that need access to either the public members of a target object (based on its runtime class) or the members declared by a given class. It also allows programs to suppress default reflective access control.cip28资讯网——每日最新资讯28at.com

Java 的反射机制是指在运行状态中,对于任意一个类都能够知道这个类所有的属性和方法;并且对于任意一个对象,都能够调用它的任意一个方法;这种动态获取信息以及动态调用对象方法的功能成为Java语言的反射机制。cip28资讯网——每日最新资讯28at.com

它是通过 Java反射 API 来实现,其中最核心的类位于 java.lang.reflect 包下,如 Class、Constructor、Field 和 Method等,这些类提供了对类和对象的运行时信息进行检查和操作的方法。如下图,展示了 JDK源码中 java.lang.reflect 包所有的类:cip28资讯网——每日最新资讯28at.com

cip28资讯网——每日最新资讯28at.com

cip28资讯网——每日最新资讯28at.com

二、反射的原理

反射的原理主要可以从下面 4个点来阐述:cip28资讯网——每日最新资讯28at.com

  • 类加载:当 Java程序运行时,类加载器会根据类的名称查找并加载类的字节码文件,然后将字节码文件转换为可执行的 Java类,并将其存储在运行时数据区域的方法区中。
  • 创建 Class对象:在类加载过程中,Java虚拟机会自动创建对应的Class对象,Class对象包含了类的元数据信息,并提供了访问和操作类的接口。
  • 获取 Class对象:Class对象通过多种方式获取,最常见的方式有 3种: 类的 .class属性、类实例的 getClass()方法、Class.forName()。
  • 访问和操作:通过Class对象获取类的字段、方法、构造函数等信息,使用Field类和Method类来访问和操作字段和方法,甚至可以调用私有的字段和方法。

通过上述的分析可以看出:反射机制需要基于Java虚拟机对类的加载、存储和访问机制的支持,通过反射,可以在运行时动态地探索和操作类的信息,实现灵活的编程和代码的动态行为。cip28资讯网——每日最新资讯28at.com

三、如何使用反射

在讲解了 Java反射原理之后,我们通过一个真实的例子来展示如何使用 Java反射机制。如下示例 demo,通过反射给 Person 类中的 greet() 方法传入一个 name,然后输出:cip28资讯网——每日最新资讯28at.com

cip28资讯网——每日最新资讯28at.com

过程分析:cip28资讯网——每日最新资讯28at.com

  • 首先,在示例代码通过获Person.class取了 Person的Class对象;
  • 然后,使用clazz.getName()获取了类的名称,通过clazz.getModifiers()获取了类的修饰符,并打印输出;
  • 接下来,通过clazz.getDeclaredMethods()获取类的所有方法,并依次打印输出方法的名称;
  • 接着,通过clazz.getDeclaredConstructor().newInstance()方法创建了 Person 的实例;
  • 再接着,使用clazz.getDeclaredMethod()方法获取了 greet()方法的引用。为了调用私有方法,我们需要调用setAccessible(true)来设置方法的可访问性。
  • 最后,使用Method.invoke()方法调用了 greet()方法,传递参数name = Java。

运行示例结果如下图:cip28资讯网——每日最新资讯28at.com

cip28资讯网——每日最新资讯28at.com

上述示例,我们通过详细的步骤展示了如何使用反射获取类的信息和动态调用方法。你也可以尝试在 Person 中添加更多的方法和字段,并使用反射来获取和操作它们。cip28资讯网——每日最新资讯28at.com

cip28资讯网——每日最新资讯28at.com

四、部分源码解读

在上述示例讲解时,最后是调用 Method.invoke() 实现 Person.greet()的调用,因此,这里我们主要分析 invoke()方案,官方源码截图:cip28资讯网——每日最新资讯28at.com

cip28资讯网——每日最新资讯28at.com

从上面源码截图看出:Method.invoke() 方法,真实返回的是接口 MethodAccessor.invoke()方法。MethodAccessor 接口有三个实现类,具体是调用哪个类的 invoke 方法?cip28资讯网——每日最新资讯28at.com

cip28资讯网——每日最新资讯28at.com

进入acquireMethodAccessor方法,可以看到MethodAccessor由ReflectionFactory 的 newMethodAccessor方法决定。cip28资讯网——每日最新资讯28at.com

cip28资讯网——每日最新资讯28at.com

cip28资讯网——每日最新资讯28at.com

再进入 DelegatingMethodAccessorImpl 的 invoke方法:cip28资讯网——每日最新资讯28at.com

cip28资讯网——每日最新资讯28at.com

DelegatingMethodAccessorImpl的invoke方法返回的是MethodAccessorImpl的invoke方法,而MethodAccessorImpl的invoke方法,由它的子类NativeMethodAccessorImpl重写,这时候返回的是native invoke0,如下图:cip28资讯网——每日最新资讯28at.com

cip28资讯网——每日最新资讯28at.com

跟到源码最后可以发现:Method.invoke()方法最终调用 native的invoke0(),应用层面的操作最终转换成对操作系统 c/c++方法的调用。cip28资讯网——每日最新资讯28at.com

五、反射优缺点

上面内容的讲解已经侧面反映出了Java反射的一些优点,这里再详细的总结下反射的优缺点:cip28资讯网——每日最新资讯28at.com

优点:cip28资讯网——每日最新资讯28at.com

  • 动态性:反射允许我们在运行时动态地获取和操作类的信息,而不需要在编译时确定。这为编写灵活的、可扩展的代码提供了便利。
  • 灵活性:通过反射,我们可以绕过访问修饰符的限制,访问和修改私有成员、调用私有方法等。这为我们在特殊情况下进行一些高级操作提供了可能。
  • 框架开发:反射在开发框架和库时非常有用。通过反射,框架可以动态地加载和实例化类,解析注解,处理回调等。这为框架提供了更大的灵活性和可扩展性。
  • 调试和探索:反射使得我们可以在运行时探索代码背后的信息,例如获取类的结构、方法、字段等。这对于调试和理解复杂的代码非常有帮助。

cip28资讯网——每日最新资讯28at.com

缺点:cip28资讯网——每日最新资讯28at.com

  • 性能开销:相比于直接调用代码,使用反射会带来更高的性能开销。反射涉及到动态查找、方法调用等操作,这些操作比直接调用代码更加耗时。因此,在对性能要求较高的场景下,过度使用反射可能导致性能下降。
  • 安全性和稳定性:反射打破了封装性和类型安全性,通过反射,我们可以绕过访问修饰符的限制,调用私有方法等,这可能导致代码的不稳定性和安全隐患。因此,使用反射时需要格外小心,确保代码的正确性和稳定性。

从整体上看,Java反射是以牺牲了小部分的性能换取了更好的扩展性和灵活性,牺牲小我成就大我,而且,随着现代硬件设备能力越来越强,这点小性能的牺牲是完全值得的。cip28资讯网——每日最新资讯28at.com

六、为什么需要反射 

反射机制在 Java中的作用不言而喻,下面列举了反射机制的一些常见场景和原因:cip28资讯网——每日最新资讯28at.com

  • 运行时类型检查:反射机制允许在运行时获取类的信息,包括字段、方法和构造方法等。因此,在进行运行时类型检查,以确保代码在处理不同类型的对象时能够正确地进行操作。
  • 动态创建对象:通过反射,可以在运行时动态地创建对象,而不需要在编译时知道具体的类名。这对于某些需要根据条件或配置来创建对象的情况非常有用,例如工厂模式或依赖注入框架。
  • 访问和修改私有成员:反射机制可以绕过访问权限限制,访问和修改类的私有字段和方法。虽然这破坏了封装性原则,但在某些特定情况下,这种能力可以帮助我们进行一些特殊操作,例如单元测试、调试或框架的内部实现。
  • 动态调用方法:反射机制允许我们在运行时动态地调用类的方法,甚至可以根据运行时的条件来选择不同的方法。这对于实现插件化系统、处理回调函数或实现动态代理等功能非常有用。
  • 框架和库的实现:许多Java框架和库在其实现中广泛使用了反射机制。它们利用反射来自动发现和加载类、实现依赖注入、处理注解、配置文件解析和动态代理等。反射机制使得这些框架和库更加灵活和扩展。

cip28资讯网——每日最新资讯28at.com

七、常用框架 

很多优秀的框架内部都使用了Java反射,这里重点讲解下给 Java打下半壁江山的 Spring生态(Spring Framework,Spring MVC,SpringBoot, SpringCloud...),以 Spring Framework为例:cip28资讯网——每日最新资讯28at.com

  • 依赖注入(Dependency Injection) : 依赖注入,可以把程序员主动创建对象的事情交给 Spring管理,大大提升了对象创建的灵活性。当我们在配置文件或用注解定义 Bean时,Spring会使用反射来动态地实例化对象,并将依赖的其他对象注入到这些实例中。
  • 自动装配(Autowired) : 当 Spring容器启动时,它会扫描应用程序中的所有类,并使用反射来查找和识别带有 @Autowired注解的字段、方法或构造函数。再自动将 Bean注入到需要的位置,实现对象之间的自动连接。
  • AOP(Aspect-Oriented Programming) : AOP 利用了动态代理和反射机制。通过定义切面(Aspect)和切点(Pointcut),Spring可以在运行时使用反射来创建代理对象,从而实现横切关注点(cross-cutting concerns)的功能,如日志记录、事务管理等。
  • 动态代理(Dynamic Proxy) : Spring利用 Java反射机制动态地创建代理对象,并在代理对象中添加额外的逻辑,从而实现对目标对象的增强。
  • 框架扩展和定制: Spring通过反射机制来实现对应用程序的扩展和定制的。例如,Spring提供了BeanPostProcessor接口,允许开发人员在 Bean初始化前后插入自定义逻辑,这是通过反射来实现的。

另外,还有一些耳熟能详的框架也使用了Java反射:cip28资讯网——每日最新资讯28at.com

  • JUnit:JUnit是一个优秀的单元测试框架,它利用了 Java反射机制动态地加载和执行测试方法。
  • Jackson:Jackson是一个 JSON处理的 Java库,它利用反射来实现 JSON与 Java对象之间的转换,动态读取和写入 Java对象的属性,并将其转换为 JSON格式。
  • Hibernate ORM:Hibernate和 MyBatis一样,都是对象关系映射框架,通过反射来实现对象与数据库表之间的映射关系。

cip28资讯网——每日最新资讯28at.com

八、总结 

cip28资讯网——每日最新资讯28at.com

本文讲解了Java反射的原理和使用方式,因为有了Java反射,很多优秀的框架应运而生,从而使得 Java 生态越来越完善,因此,反射是绝大多数框架的基石。cip28资讯网——每日最新资讯28at.com

Java反射有优点也有缺点,从整体上看,Java反射是以牺牲了小部分的性能换取了更好的扩展性和灵活性,牺牲小我成就大我,而且,随着现代硬件设备能力越来越强,这点小性能的牺牲是完全值得的。cip28资讯网——每日最新资讯28at.com

掌握Java反射,我们可以更好的理解一些优秀框架的运行机制,比如:Spring。它可以帮助我们更好的使用框架,遇到问题时也能更好的去分析和解决。cip28资讯网——每日最新资讯28at.com

本文链接:http://www.28at.com/showinfo-26-90660-0.htmlJava 反射:让你更优雅的使用框架!

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: Python 中 URL 处理的常见问题及解决方案,值得收藏!

下一篇: 京东面试:SpringBoot同时可以处理多少请求?

标签:
  • 热门焦点
  • 0糖0卡0脂 旭日森林仙草乌龙茶优惠:15瓶到手29元

    旭日森林无糖仙草乌龙茶510ml*15瓶平时要卖为79.9元,今日下单领取50元优惠券,到手价为29.9元。产品规格:0糖0卡0脂,添加草本仙草汁,清凉爽口,富含茶多酚,保留
  • 十个可以手动编写的 JavaScript 数组 API

    JavaScript 中有很多API,使用得当,会很方便,省力不少。 你知道它的原理吗? 今天这篇文章,我们将对它们进行一次小总结。现在开始吧。1.forEach()forEach()用于遍历数组接收一参
  • 线程通讯的三种方法!通俗易懂

    线程通信是指多个线程之间通过某种机制进行协调和交互,例如,线程等待和通知机制就是线程通讯的主要手段之一。 在 Java 中,线程等待和通知的实现手段有以下几种方式:Object 类下
  • 2023 年的 Node.js 生态系统

    随着技术的不断演进和创新,Node.js 在 2023 年达到了一个新的高度。Node.js 拥有一个庞大的生态系统,可以帮助开发人员更快地实现复杂的应用。本文就来看看 Node.js 最新的生
  • .NET 程序的 GDI 句柄泄露的再反思

    一、背景1. 讲故事上个月我写过一篇 如何洞察 C# 程序的 GDI 句柄泄露 文章,当时用的是 GDIView + WinDbg 把问题搞定,前者用来定位泄露资源,后者用来定位泄露代码,后面有朋友反
  • 每天一道面试题-CPU伪共享

    前言:了不起:又到了每天一到面试题的时候了!学弟,最近学习的怎么样啊 了不起学弟:最近学习的还不错,每天都在学习,每天都在进步! 了不起:那你最近学习的什么呢? 了不起学弟:最近在学习C
  • 本地生活这块肥肉,拼多多也想吃一口

    出品/壹览商业 作者/李彦编辑/木鱼拼多多也看上本地生活这块蛋糕了。近期,拼多多在App首页“充值中心”入口上线了本机生活界面。壹览商业发现,该界面目前主要
  • iQOO Neo8 Pro即将开售:到手价3099元起 安卓性能最强旗舰

    5月23日,iQOO如期举行了新品发布会,全新的iQOO Neo8系列也正式与大家见面,包含iQOO Neo8和iQOO Neo8 Pro两个版本,其中标准版搭载高通骁龙8+,而Pro版更
  • OPPO K11搭载高性能石墨散热系统:旗舰同款 性能凉爽释放

    日前OPPO官方宣布,将于7月25日14:30举办新品发布会,届时全新的OPPO K11将正式与大家见面,将主打旗舰影像,和同档位竞品相比,其最大的卖点就是将配备索尼
Top