2019独角兽企业重金招聘Python工程师标准>>>

方法反射实例

public class ReflectCase {

public static void main(String[] args) throws Exception {

Proxy target = new Proxy();

Method method = Proxy.class.getDeclaredMethod("run");

method.invoke(target);

}

static class Proxy {

public void run() {

System.out.println("run");

}

}

}

通过Java的反射机制,可以在运行期间调用对象的任何方法,如果大量使用这种方式进行调用,会有性能或内存隐患么?为了彻底了解方法的反射机制,只能从底层代码入手了。

Method获取

调用Class类的getDeclaredMethod可以获取指定方法名和参数的方法对象Method。

getDeclaredMethod

其中privateGetDeclaredMethods方法从缓存或JVM中获取该Class中申明的方法列表,searchMethods方法将从返回的方法列表里找到一个匹配名称和参数的方法对象。

searchMethods

如果找到一个匹配的Method,则重新copy一份返回,即Method.copy()方法

所次每次调用getDeclaredMethod方法返回的Method对象其实都是一个新的对象,且新对象的root属性都指向原来的Method对象,如果需要频繁调用,最好把Method对象缓存起来。

privateGetDeclaredMethods

从缓存或JVM中获取该Class中申明的方法列表,实现如下:

其中reflectionData()方法实现如下:

这里有个比较重要的数据结构ReflectionData,用来缓存从JVM中读取类的如下属性数据:

从reflectionData()方法实现可以看出:reflectionData对象是SoftReference类型的,说明在内存紧张时可能会被回收,不过也可以通过-XX:SoftRefLRUPolicyMSPerMB参数控制回收的时机,只要发生GC就会将其回收,如果reflectionData被回收之后,又执行了反射方法,那只能通过newReflectionData方法重新创建一个这样的对象了,newReflectionData方法实现如下:

通过unsafe.compareAndSwapObject方法重新设置reflectionData字段;

在privateGetDeclaredMethods方法中,如果通过reflectionData()获得的ReflectionData对象不为空,则尝试从ReflectionData对象中获取declaredMethods属性,如果是第一次,或则被GC回收之后,重新初始化后的类属性为空,则需要重新到JVM中获取一次,并赋值给ReflectionData,下次调用就可以使用缓存数据了。

Method调用

获取到指定的方法对象Method之后,就可以调用它的invoke方法了,invoke实现如下:

应该注意到:这里的MethodAccessor对象是invoke方法实现的关键,一开始methodAccessor为空,需要调用acquireMethodAccessor生成一个新的MethodAccessor对象,MethodAccessor本身就是一个接口,实现如下:

在acquireMethodAccessor方法中,会通过ReflectionFactory类的newMethodAccessor创建一个实现了MethodAccessor接口的对象,实现如下:

在ReflectionFactory类中,有2个重要的字段:noInflation(默认false)和inflationThreshold(默认15),在checkInitted方法中可以通过-Dsun.reflect.inflationThreshold=xxx和-Dsun.reflect.noInflation=true对这两个字段重新设置,而且只会设置一次;

如果noInflation为false,方法newMethodAccessor都会返回DelegatingMethodAccessorImpl对象,DelegatingMethodAccessorImpl的类实现

其实,DelegatingMethodAccessorImpl对象就是一个代理对象,负责调用被代理对象delegate的invoke方法,其中delegate参数目前是NativeMethodAccessorImpl对象,所以最终Method的invoke方法调用的是NativeMethodAccessorImpl对象invoke方法,实现如下:

这里用到了ReflectionFactory类中的inflationThreshold,当delegate调用了15次invoke方法之后,如果继续调用就通过MethodAccessorGenerator类的generateMethod方法生成MethodAccessorImpl对象,并设置为delegate对象,这样下次执行Method.invoke时,就调用新建的MethodAccessor对象的invoke()方法了。

这里需要注意的是:

generateMethod方法在生成MethodAccessorImpl对象时,会在内存中生成对应的字节码,并调用ClassDefiner.defineClass创建对应的class对象,实现如下:

在ClassDefiner.defineClass方法实现中,每被调用一次都会生成一个DelegatingClassLoader类加载器对象

这里每次都生成新的类加载器,是为了性能考虑,在某些情况下可以卸载这些生成的类,因为类的卸载是只有在类加载器可以被回收的情况下才会被回收的,如果用了原来的类加载器,那可能导致这些新创建的类一直无法被卸载,从其设计来看本身就不希望这些类一直存在内存里的,在需要的时候有就行了。

转载于:https://my.oschina.net/u/2441327/blog/872994

深入分析 Java 方法反射的实现原理相关推荐

  1. Java方法反射的实现原理

    反射方面先看Java反射与动态代理 "物有本末,事有始终.知其先后,则近道矣" 前段时间看了笨神的 从一起GC血案谈到反射原理一本,就把Java方法的反射机制实现撸了一遍. 方法反 ...

  2. 揭密 Java方法调用的底层原理

    关注公众号"java后端技术全栈" 回复"000"获取优质面试资料 大家好,我是老田,今天来和大家聊聊Java方法调用的底层原理. 我们在日常开发中,其实很少去 ...

  3. 好文推荐:深入分析Java线程池的实现原理

    线程是稀缺资源,如果被无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,合理的使用线程池对线程进行统一分配.调优和监控,有以下好处: 1.降低资源消耗: 2.提高响应速度: 3.提高线程的可管理 ...

  4. 没有与参数列表匹配的 重载函数 getline 实例_面试题:方法重载的底层原理?...

    前语:微信改版后,大量读者还没养成点赞的习惯,如写得好,望大家阅读后在右下边"好看"处点个赞,以示鼓励!长期坚持原创真的很不容易,多次想放弃,坚持是一种信仰,专注是一种态度. 关于 ...

  5. 【java】深入分析Java反射-动态代理 proxy

    1.概述 转载:深入分析Java反射(四)-动态代理 [Java]Java 反射机制浅析 [Java]java代理 静态代理 动态代理 proxy [java]静态代理 proxy 2.动态代理的简介 ...

  6. JAVA反射机制及其原理实现

    9.1 概念 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意方法和属性:public.protected.private. OO ...

  7. 【重难点】【Java基础 05】说一说你平时遇到的异常、什么情景下会用到反射、反射的底层原理

    [重难点][Java基础 05]说一说你平时遇到的异常.什么情景下会用到反射.反射的底层原理 文章目录 [重难点][Java基础 05]说一说你平时遇到的异常.什么情景下会用到反射.反射的底层原理 一 ...

  8. Java反射及 IoC原理、内省机制

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

  9. Java反射机制的原理及作用

    反射机制是Java特性之一,反射机制是构建框架技术的基础所在.灵活掌握Java反射机制,对大家以后学习框架技术有很大的帮助. 那么什么是Java的反射呢? 大家都知道,要让Java程序能够运行,那么就 ...

最新文章

  1. 7.1 pdo 宝塔面板php_记宝塔面板中 PHP升级到 7.3.16安全版本概要
  2. mysql 绑定参数_MySQL 使用 Perl 绑定参数和列
  3. python with 打开多个文件
  4. 根据端口不同来切换站点_KVM切换器是什么,看懂这一篇就够
  5. 笔记-高项案例题-2016年下-整体管理
  6. 研发大佬组团带玩生成对抗网络(GAN),B站直播教学
  7. cscope使用命令
  8. android 常用注解,Android 开发小工具之:注解 Annotation
  9. Apache的多处理模块MPM
  10. php的对象和数组应该学js,JavaScript数组与对象的常用方法及 json 的序列化
  11. bzoj 5281: [Usaco2018 Open]Talent Show【dp】
  12. 国二office计算机基础知识,国二office计算机基础知识选择题
  13. php js轮播图片代码,html中用JS实现图片轮播的实例代码
  14. Roslyn 入门:使用 Roslyn 静态分析现有项目中的代码
  15. 《我想进大厂》之分布式锁夺命连环9问 | 大理版人在囧途
  16. 小程序关注微信公众号的方法
  17. Mardown、LaTex编辑器推荐
  18. Android开发 读取手机通讯录
  19. 大数据之Hadoop3.x 运行环境搭建(手把手搭建集群)
  20. 【bzoj4567】[Scoi2016]背单词 贪心+trie树

热门文章

  1. [转] c#中 多线程访问winform控件
  2. Sublime Text 3118 集成插件汉化定制版——赵亮(碧海情天)
  3. 使用JavaStcript对数组元素去重的方法
  4. 常见多媒体文件格式及视音频编解码总结
  5. 分区表学习一:分区表介绍
  6. FreeMarker Eclipse Plugin的安装!
  7. 安装Nacos Server
  8. 【思考?】什么时候会触发这个策略呢?
  9. 简单了解各种序列化技术-Avro序列化
  10. Redis中的Sentinel 验证