JVM中是如何实现反射的

前言1: 反射常用的API介绍:

获取class对象

  1. 调用静态方法Class.forName来获取
  2. 调用对象的getClass()方法
  3. 直接调用类名 + ".class"访问。对于基本类型而言,它们的包装类型拥有一个名为‘TYPE'的final静态字段,指向该基本类型对应的Class对象

例如,Integer.TYPE指向int.class.对于数组类型来说,可以使用类名 + "[].class"来访问,例如int[].class

一旦获取到Class对象,我们便可以正式的使用反射功能了,常用的几项:

  1. 使用newintznce()来生成一个该类的实例。它要求该类中拥有一个无参数的构造器。

  2. 使用isInstance(Object)来判断一个对象是否为该类的实例,语法上等同于instance of

  3. 使用Array.newInstance(Class,int) 来构建该类型的数组

  4. 使用getFIleds()/getConstructors()/getMethods()来访问该类的成员。方法名中带Declared的不会返回父类的成员,但是会返回私有成员,而带有Declared的则相反。

当获得了类成员之后,我们可以进一步的操作

  1. 使用Construct/Field/Method.setAccessible(true) 来绕开Java语言的访问限制
  2. 使用Construct.newInstance(Object[])来生成该类的实例
  3. 使用Field.get()/set(Object)来访问字段的值
  4. 使用Method.invoke(Object,Object[])来调用方法

前言2:内联的概念解释

方法内联指的是编译器在编译一个方法时,将某个方法调用的目标方法也纳入编译范围内,并用返回值 替代方法调用的过程。

接下来聊一聊反射

反射机制在java中的应用: ide的提示功能、java调试器,一些可配置的通用框架为了保证其可扩展性,往往借助Java的反射机制根据配置文件加载不同的类。例如Spring框架的依赖反转(ioc)便是依赖于反射机制。

但是反射机制也有它显著的缺点:性能开销大

那么反射是怎么实现的呢?看一看Method.invoke()的调用

查阅Method.invoke的源代码可以发现,它实际上会委托给MethodAccessor来处理。MethodAccessor是一个接口,它有两个具体的实现:一个通过本地方法实现反射,另一个则使用了委派模式。

每个Method实例的第一次反射调用都会生成一个委派实现,它所委派的具体实现便是一个本地实现。本地实现非常容易理解,当进入了java虚拟机内部的时候,我们便拥有了Method实例所指向方法的具体地址,这时候反射调用无非就是将传入的参数准备好,然后调用进入目标方法。

打印反射调用的栈轨迹可以发现,反射调用先是调用了Method.invoke,然后进入委派实现(DelegatingMethodAccessorImpl),再然后进入本地方法实现(NativeMethodAccessorImpl)最后到达目标方法.

那么,为什么反射调用还要采取委派实现作为中间层?直接交给本地实现不可以吗?

其实,java反射调用机制还设立了另一种动态生成字节码的实现(动态实现),直接使用invoke指令来调用目标方法,之所以采用委派实现,便是为了能够在本地实现以及动态实现中切换。(可以联想动态代理的invoke)

动态实现与本地实现相比,运行效率要快上20倍,因为动态实现无需经过java到c++再到java的切换,但由于生成字节码十分耗时,仅调用一次的话,反而使用本地实现要快上3到4倍。

考虑到许多反射调用仅会执行一次,java虚拟机设置了一个阈值15(-Dsun.reflect.inflationThreshold= ? )来调整,当某个反射调用的调用次数在15次之下的时候,采用本地实现,当达到15时,便开始动态生成字节码,并将委派实现的委派对象切换至动态实现,这个过程称之为inflation.

总结一下反射调用的性能开销

方法的反射调用会带来不少的性能开销,原因主要有三个,变长参数方法导致的Object数组,基本类型的自动装箱、拆箱还有最重要的方法内联。

以上内容是我对极客时间郑雨迪老师<<深入拆解Java虚拟机>>的精简版总结。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,997评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,603评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,359评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,309评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,346评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,258评论 1 300
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,122评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,970评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,403评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,596评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,769评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,464评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,075评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,705评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,848评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,831评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,678评论 2 354

推荐阅读更多精彩内容