从一段示例代码开始

        Class clz = Class.forName("ClassA");Object instance = clz.newInstance();Method method = clz.getMethod("myMethod", String.class);method.invoke(instance, "abc","efg");

前两行实现了类的装载、链接和初始化(newInstance方法实际上也是使用反射调用了<init>方法),后两行实现了从class对象中获取到method对象然后执行反射调用。试想一下,如果Method.invoke方法内,动态拼接成如下代码,转化成JVM能运行的字节码,就可以实现反射调用了。

     public Object invoke(Object obj, Object[] param){MyClass instance=(MyClass)obj;return instance.myMethod(param[0],param[1],...);}

Class和Method对象

Class对象里维护着该类的所有Method,Field,Constructor的cache,这份cache也可以被称作根对象。每次getMethod获取到的Method对象都持有对根对象的引用,因为一些重量级的Method的成员变量(主要是MethodAccessor),我们不希望每次创建Method对象都要重新初始化,于是所有代表同一个方法的Method对象都共享着根对象的MethodAccessor,每一次创建都会调用根对象的copy方法复制一份:

    Method copy() { Method res = new Method(clazz, name, parameterTypes, returnType,exceptionTypes, modifiers, slot, signature,annotations, parameterAnnotations, annotationDefault);res.root = this;res.methodAccessor = methodAccessor;return res;}

反射调用

    public Object invoke(Object obj, Object... args)throws IllegalAccessException, IllegalArgumentException,InvocationTargetException{if (!override) {if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {Class<?> caller = Reflection.getCallerClass();checkAccess(caller, clazz, obj, modifiers);}}MethodAccessor ma = methodAccessor;             // read volatileif (ma == null) {ma = acquireMethodAccessor();}return ma.invoke(obj, args);}

调用Method.invoke之后,先进行访问权限检查,再获取MethodAccessor对象,并调用MethodAccessor.invoke方法。MethodAccessor被同名Method对象所共享,由ReflectionFactory创建。创建机制采用了一种名为inflation的方式(JDK1.4之后):如果该方法的累计调用次数<=15,会创建出NativeMethodAccessorImpl,它的实现就是直接调用native方法实现反射;如果该方法的累计调用次数>15,会创建出由字节码组装而成的MethodAccessorImpl。(是否采用inflation和15这个数字都可以在jvm参数中调整)

那么以示例的反射调用ClassA.myMethod(String,String)为例,生成MethodAccessorImpl类的字节码对应成Java代码如下:

public class GeneratedMethodAccessor1 extends MethodAccessorImpl {    public Object invoke(Object obj, Object[] args)  throws Exception {try {MyClass target = (ClassA) obj;String arg0 = (String) args[0];String arg1 = (String) args[1];target.myMethod(arg0,arg1);} catch (Throwable t) {throw new InvocationTargetException(t);}}
}

性能

通过JNI调用native方法初始化更快,但对优化有阻碍作用。随着调用次数的增多,使用拼装出的字节码可以直接以Java调用的方式来实现反射,发挥了JIT的优化作用。

那么为什么Java反射调用被普通的方法调用慢很多呢?我认为主要有以下三点原因:

  1. 因为接口的通用性,Java的invoke方法是传object和object[]数组的。基本类型参数需要装箱和拆箱,产生大量额外的对象和内存开销,频繁促发GC。
  2. 编译器难以对动态调用的代码提前做优化,比如方法内联。
  3. 反射需要按名检索类和方法,有一定的时间开销。

参考

  • http://www.fanyilun.me/2015/10/29/Java%E5%8F%8D%E5%B0%84%E5%8E%9F%E7%90%86/
  • http://rednaxelafx.iteye.com/blog/548536

浅谈Java反射的实现原理相关推荐

  1. 浅谈Java反射机制 之 获取类的字节码文件 Class.forName(全路径名) 、getClass()、class...

    先贴上Java反射机制的概念: AVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法: 对于任意一个对象,都能够调用它的任意一个方法和属性: 这种动态获取的信息以及动态调用对 ...

  2. 浅谈Java反射(Reflect)技术--常用方法

    Java反射(Reflect)技术 概念:动态获取在当前Java虚拟机中的类.接口或者对象等等信息(运行过程中读取内容) 1.作用(面试问题): 1.1 解除两个类之间的耦合性,即在未得到依赖类的情况 ...

  3. java反射 用处_浅谈Java反射

    一.何为反射 反射就是对于任何一个类都能知道这个类的的所有属性和方法,并且对于任何一个对象都能调用他的属性和方法,而且能修改其属性. 二.反射的作用 就我的理解来看,通常我们在写代码的时会非常强调代码 ...

  4. java bitset用途_浅谈Java BitSet使用场景和代码示例

    搜索热词 @H_502_0@一.什么是BitSet? @H_502_0@ 注:以下内容来自JDK API: @H_502_0@ BitSet类实现了一个按需增长的位向量.位Set的每一个组件都有一个b ...

  5. java虚拟机类加载机制浅谈_浅谈Java虚拟机(三)之类加载机制

    在<浅谈Java虚拟机>这篇文章中,我们提到了JVM从操作系统方面来说,可以将其看做是一个进程,分别有类加载器子系统,执行引擎子系统和垃圾收集子系统.这一篇文章就简单的来谈一下类加载器子系 ...

  6. 常在池边游,却不曾到池子里一探究竟?浅谈Java线程池

    浅谈Java线程池 线程池,简单来说,就是一个池子嘛,里面养着一群线程,ABCD........,然后你要用的时候,从里面拿一个去用,用完放回去. 一群人要用的时候,每个人都从池子里面拿一个线程,当池 ...

  7. java 中的排序_浅谈java中常见的排序

    浅谈java中常见的排序 学过java的人都知道,排序这一部分初次接触感觉还是有点难以理解,很多地方也会用到.然而,在java中常见的排序方法:冒泡排序,选择排序,插入排序等等.下面就让我们一起揭开他 ...

  8. java 中的单元测试_浅谈Java 中的单元测试

    单元测试编写 Junit 单元测试框架 对于Java语言而言,其单元测试框架,有Junit和TestNG这两种, 下面是一个典型的JUnit测试类的结构 package com.example.dem ...

  9. java的byte php_java_浅谈java的byte数组的不同写法,(由于篇幅原因阐述的不够详 - phpStudy...

    浅谈java的byte数组的不同写法 (由于篇幅原因阐述的不够详细科学,不喜勿喷). 经常看到java中对byte数组的不同定义,粗略整理的一下: 一个字节(byte)=8位(bit),"b ...

最新文章

  1. 【UIKit】TabView
  2. 2021-01-07 matlab数值分析 线性方程组的迭代解法 高斯-赛德尔迭代法
  3. Extjs4.2——Panel
  4. 51Nod1079 中国剩余定理
  5. 约瑟夫环递推公式的由来(约瑟夫环公式法)
  6. accsess转成mysql语句_轻松教你SQL转ACCESS
  7. 浙江省高等学校计算机等级考试有什么用,06秋年秋浙江省高等学校计算机等级考试试卷(三级数据库技术及应用)...
  8. java阿里系学习经历的小小领悟
  9. jqgrid for asp.net 遍历所有列rowObject时不用输入编号
  10. Apache Commons Pool试用小记
  11. java 调试js_Java与JS代码调试技巧
  12. jquery创建添加append、prepend、appendTo、prependTo、after、insertAfter、before、insertBefore
  13. 登录emc磁阵提示java版本低_安装完打开 eclipse 提示 JVM 版本较低
  14. MySQL创建数据库、数据表 | 零基础自学SQL课程系列Day3
  15. MFC中CDC *PDC hDC 等等及Wnd的区别
  16. 关于冯诺依曼结构、哈佛结构、增强型的哈佛结构
  17. 笔记本电脑外放没声音,或外放有声音/插耳机没声音———Realtek High Definition Audio Driver安装
  18. ‘xxx‘ is assigned a value but never used.
  19. 聊聊程序员的成长与如何实现价值提升
  20. 使用Linkage Mapper制作环境连接图

热门文章

  1. 用网页打开本地exe程序
  2. 将CSS文件转换为标准格式
  3. 【科研杂记_3】测高卫星
  4. 阿里巴巴十年Java架构师分享,会了这个知识点的人都去BAT了
  5. ​UG塑胶模具设计结构分析是如何挤压成型的
  6. vue 中 highcharts 的简单使用
  7. 福大携手移动云,共启数字教育新篇章!
  8. 3D游戏设计-智能巡逻兵
  9. arm为何断供华为?华为会使用RISC-V取代ARM?
  10. 面试心得(简历书写)