反射是Java中的一个重要的特性,使用反射可以在运行时动态生成对象、获取对象属性以及调用对象方法。与编译期的静态行为相对,所有的静态型操作都在编译期完成,而反射的所有行为基本都是在运行时进行的,这是一个很重要的特性。它让Java有了动态特性,可以让程序更加灵活强大。

本篇文章针对Java的反射基本原理做一些探究,以期对Java的反射机制有较为清晰的认识。

由于网上的源码级的博客很多,本篇文章主要总结思想,故不会大篇幅的探究源码,但作者的认知是建立在对源码的探究之上的,所以有条件的读者一定要去大体看看源码

反射的背景和应用

使用反射的背景

反射大量运用在框架代码和工具代码中,因为这类工程项目往往对于灵活性的要求较高,在实际的业务代码中我们其实使用反射并不多。因此这也就引出了,大部分时候做业务的我们为什么要学习反射原理的原因:为了更加深刻地理解我们所用的工具和框架,了解了反射原理,我们能够在使用框架时优化出更好的性能,遇到问题能及时定位排错,这些都是很重要的。

反射的具体应用

  • 原来使用new的时候,需要明确的指定类名,这个时候属于硬编码实现,而在使用反射的时候,可以只传入类名参数,就可以生成对象,降低了耦合性,使得程序更具灵活性。关于这一点的实例有:简单工厂模式的优化、Spring框架中Bean的创建、动态代理的实现等。
  • 原来并未使用反射时,我们没办法在运行时动态获取/修改一个类的所有属性,而通过反射机制,我们能够在运行时确定类的状态和属性,这为灵活操作提供了空间。具体的实例有:运行时根据类的状态进行异常监测,突破封装限制获取修改private、protected属性,这点在IDE的调试器中就有应用。

反射API

这部分不会讲太详细的API使用,只提及一些API中的重要基本概念(因为讲原理时候会用),掌握了原理后再去看这些API会非常简单。

反射API中比较重要的概念有:

  • Class类:Java程序在编译完成后,会把所有class文件中所包含的类的基本元信息装载到JVM内存中,以Class类的形式保存,每一个Class类对象代表一个具体类的基本元信息。我们的反射就是在Class类的基础上进行的,Class类对象存储着类的所有相关信息,就像镜子,故称“反射”。
  • Field:即类或对象的域,就是属性值
  • Method:类或对象的方法
  • Constructor:类或对象的构造器,使用它可以构造出相应的类对象

反射基本原理

整体流程

调用反射的总体流程如下:

  • 准备阶段:编译期装载所有的类,将每个类的元信息保存至Class类对象中,每一个类对应一个Class对象
  • 获取Class对象:调用x.class/x.getClass()/Class.forName() 获取x的Class对象clz(这些方法的底层都是native方法,是在JVM底层编写好的,涉及到了JVM底层,就先不进行探究了)
  • 进行实际反射操作:通过clz对象获取Field/Method/Constructor对象进行进一步操作

整体过程中,需要注意的是进行实际反射操作的这个阶段,我们需要关注的点有:

  • 我们是如何通过Class获取到Field/Method/Construcor的?
  • 获取到的Field是如何具有对象属性值的?
  • 获取到的Method是如何调用的?

下面就来详细解释这些问题:

如何通过Class获取Field/Method/Construcor

探究Class类源码的时候,我们发现Class类中包含的ReflectionData,用于保存进行反射操作的基础信息

这显然是我们获取Field/Method/Constructor的直接来源,那么这个数据结构中的值又是从哪里来的呢?我们以Field的获取为例进行探究,我们先看看getDeclaredField这个方法:

内部调用了privateGetDeclaredFields方法,我们进去看:

第一处是从reflectionData直接取,reflectionData是弱引用,这算是一种缓存获取;第二处是直接调用getDeclaredFields0()这个方法获取,这是一个native方法,应当是从JVM内直接获取

至于Method和Constructor的获取则是大同小异,

至此我们基本搞清楚了Class是如何获取Field/Method/Constructor的了

Field是如何具有对象属性值

很显然,因为Field对象是来自JVM的,JVM中自然保存着对象的详细属性值,因此通过反射获取到的Field就能包含着原始对象的属性值

获取到的Method如何调用

通过对源码的查看,调用Method的过程大致如下:

如上图所示,我们大致经历了一个这样的过程:

  • Method对象通过MethodAcessor的invoke调用方法 ->
  • 通过反射工厂生成MethodAcessor对象 ->
  • 生成NativeMethodAcessorImpl,最终由DelegatingMethodAccessorImpl代理 ->
  • 调用时先进入的是DelegatingMethodAccessorImpl的invoke方法 ->
  • DelegatingMethodAcessorImpl是代理对象,实质上最终调用的是NativeMethodAcessorImpl的invoke方法
  • 所有的方法反射都是先走NativeMethodAccessorImpl,默认调了15次之后,才生成一个GeneratedMethodAccessorXXX类,生成好之后就会走这个生成的类的invoke方法了

最后一点调用十五次阈值的原因在于:存在两种MethodAcessor,Native 版本一开始启动快,但是随着运行时间边长,速度变慢。Java 版本一开始加载慢,但是随着运行时间边长,速度变快。正是因为两种存在这些问题,所以第一次加载的时候我们会发现使用的是 NativeMethodAccessorImpl 的实现,而当反射调用次数超过 15 次之后,则使用 MethodAccessorGenerator 生成的 MethodAccessorImpl 对象去实现反射。

这其实是借助代理模式实现了一个性能优化手段,这种利用代理模式灵活适配的思想很值得学习

结语

到了这里,基本介绍完了反射机制的原理,由于动态代理的底层本质就是反射机制,因此下篇文章我会在本篇文章的基础上对Java的动态代理实现原理做一些探究。

参考资料

https://www.cnblogs.com/chanshuyi/p/head_first_of_reflection.htmlhttps://www.jianshu.com/p/3ea4a6b57f87https://mp.weixin.qq.com/s/5H6UHcP6kvR2X5hTj_SBjA

java 反射机制_Java反射机制原理探究相关推荐

  1. java 内省机制_Java反射及 IoC原理、内省机制

    JAVA反射及IoC原理.JAVA内省 1. 反射反射是框架设计的灵魂,使用前提:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码文件). 1.1 反射概述主要指程序可 ...

  2. java 反射代价_Java反射机制

    # 反射 ## 什么是反射 反射是Java提供的动态执行机制, 可以动态加载类, 动态创建对象, 动态访问属性, 动态调用方法.. 静态执行: Java代码经过编译以后就确定的执行次序, 称为静态执行 ...

  3. java反射模式_Java反射机制详解

    对于一般的开发者,很少需要直接使用Java反射机制来完成功能开发,但是反射是很多框架譬如 Spring, Mybatis 实现的核心,反射虽小,能量却很大. 本文主要介绍反射相关的概念以及API的使用 ...

  4. Java的反射作用_java反射机制的作用与优点

    java的反射机制就是增加程序的灵活性,避免将程序写死到代码里, 例如: 实例化一个 person()对象, 不使用反射, new person(); 如果想变成 实例化 其他类, 那么必须修改源代码 ...

  5. java的两种运行机制_Java☞JVM工作原理

    参考博客:1 2 3 JVM工作原理 java虚拟机体系结构 Java平台由Java虚拟机和Java应用程序接口搭建,Java语言则是进入这个平台的通道,用Java语言编写并编译的程序可以运行在这个平 ...

  6. java反射类型转换_java反射(转)

    反射是框架设计的灵魂 (使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码)) 一.反射的概述 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道 ...

  7. java反射类型转换_Java反射探索研究(转)

    林炳文Evankaka原创作品.转载请注明出处http://blog.csdn.net/evankakay 摘要:本文详细深入讲解是Java中反射的机制,并介绍了如何通过反射来生成对象.调用函数.取得 ...

  8. Java内省用法_java内省机制及PropertyUtils使用方法

    反射 相对而言,反射比内省更容易理解一点.用一句比较白的话来概括,反射就是让你可以通过名称来得到对象(类,属性,方法)的技术.例如我们可以通过类 名来生成一个类的实例:知道了方法名,就可以调用这个方法 ...

  9. java 反射练习_JAVA反射的基础学习

    反射 :reflection 程序的一种内省机制 程序可以在运行期间动态的创建对象,获取对象类型,调用对象行为 内省机制在java和.net语言中有,在早期的C,C++,delphi,vb这些语言都没 ...

最新文章

  1. opengl加载显示3D模型X3D类型文件
  2. Redis分布式锁原理解析
  3. ftp服务器上传文件提示451,解决IIS7之FTP部分文件上传451错误
  4. 阿里云服务器Debian11系统安装Linux宝塔面板 搭建WordPress个人博客
  5. JWT token生成原理
  6. 详解 Qt 串口通信程序全程图文 (3)
  7. 服务器Context、虚拟主机配置(管理、配置)
  8. hihocoder编程练习赛91:相邻字符串
  9. java对mysql进行查找替换_java对mysql的增删改查
  10. Google云端语音识别app
  11. Mesa 3D 计算机图形库
  12. matlab2018历史命令在哪,2018美赛准备之路——Matlab基础——命令行功能函数
  13. IDEA远程调试代码
  14. 甲方爸爸素材给得少,怎么做出高大上的设计?
  15. 开源一款资源分享与下载工具 —— 电驴(eMule)
  16. 在 WSO2 ESB 5.0.0 中使用 MyBatis 框架
  17. modelica学习
  18. 2018VMware虚拟机安装ghost win7系统正确方法
  19. 2022年上半年财神爷最爱照顾的星座
  20. 猿创征文 | 什么是PHP,PHP如何创建数据库

热门文章

  1. sklearn RandomForest(随机森林)模型使用RandomSearchCV获取最优参数及模型效能可视化
  2. c语言easy,C语言easy….doc
  3. linux ip -o,linux IP 命令使用举例
  4. mxnet报错解决:AttributeError: module 'mxnet.context' has no attribute 'num_gpus'
  5. keras和tensorflow使用 keras.callbacks.EarlyStopping 提前结束训练
  6. Docker创建Gitea(git服务)
  7. java urlstreamhandler_获取对Java的默认http(s)URLStreamHandler的引用
  8. 计算机对文字信息交流方式案例,《信息交流的方式》题本梳理_教师资格面试初中信息技术...
  9. 多路复用 I/O 模型详解, 为什么他能支持更高的并发
  10. Docker(十五):Docker实战 使用 docker-compose