java-反射深度剖析
Java反射是Java语言一个很重要的特征,简单剖析下反射的定义、原理、使用、性能及应用场景。
(一)定义
程序运行时,允许改动程序结构或变量类型,这种语言称为动态语言。java不属于动态语言,但提供了RTTI(Run-time Type Identification)运行时类别识别。RTTI分为两种方式,一种是编译运行时已知悉类型,一种是反射机制。
(二)原理
在《深入java虚拟机》中提到,java文件被编译成class文件,JVM类加载器加载class字节码到方法区,然后在堆中生成Class类,Class类可以访问到类的基本信息,如类简单名、类包含路径全名、访问修饰符、字段、方法等信息。
反射中需要使用到的类:
Field类:提供有关类或接口的属性的信息,以及对它的动态访问权限。反射的字段可能是一个类(静态)属性或实例属性,简单的理解可以把它看成一个封装反射类的属性的类。
Constructor类:提供关于类的单个构造方法的信息以及对它的访问权限。这个类和Field类不同,Field类封装了反射类的属性,而Constructor类则封装了反射类的构造方法。
Method类:提供关于类或接口上单独某个方法的信息。所反映的方法可能是类方法或实例方法(包括抽象方法)。
Class类:类的实例表示正在运行的 Java 应用程序中的类和接口。枚举是一种类,注释是一种接口。每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。
(三)使用
(1)获取Class
方法一:Class c=Class.forName("java.lang.String")
方法二:对于基本数据类型可以用形如Class c=int.class或Class c=Integer.TYPE的语句
(tips:int.class = Integer.TYPE !=Integer.class)
方法三:Class c=MyClass.class
(2)调用Class中的方法得到你想得到的信息集合,如调用getDeclaredFields()方法得到类所有的属性
- Field field = classInstance.getDeclaredField("TEST_TIMES");
- int times = (Integer) field.get(classInstance);
- System.out.println(times);
(四)性能
反射的性能是低于直接调用的,下次通过测试验证这个结果,测试中尽量避免对象创建等干扰因素。
我们将测试直接访问的耗时、直接反射的耗时、缓存需要查找的函数反射的耗时、使用ReflectAsm的反射耗时。
- /**
- * 测试反射性能
- *
- * @author peter_wang
- * @create-time 2014-6-13 下午12:54:52
- */
- public class ReflectPerformanceDemo {
- private static final int TEST_TIMES = 1000000;
- private long mNum;
- private long mSum;
- /**
- * @param args
- */
- public static void main(String[] args) {
- normalInvoke();
- normalReflectInvoke();
- cacheReflectInvoke();
- asmReflectInvoke();
- }
- /**
- * 正常调用方法
- */
- private static void normalInvoke() {
- ReflectPerformanceDemo demo = new ReflectPerformanceDemo();
- long time1 = System.currentTimeMillis();
- for (long i = 0; i < TEST_TIMES; i++) {
- demo.setmNum(i);
- demo.mSum += demo.getmNum();
- }
- long time2 = System.currentTimeMillis();
- System.out.println("normal invoke time:" + (time2 - time1));
- }
- /**
- * 常规反射调用方法
- */
- private static void normalReflectInvoke() {
- ReflectPerformanceDemo demo = new ReflectPerformanceDemo();
- long time1 = System.currentTimeMillis();
- try {
- for (long i = 0; i < TEST_TIMES; i++) {
- Class<?> c = Class.forName("com.peter.demo.process.reflect.ReflectPerformanceDemo");
- Method method = c.getMethod("setmNum", Long.TYPE);
- method.invoke(demo, i);
- demo.mSum += demo.getmNum();
- }
- }
- catch (Exception e) {
- e.printStackTrace();
- }
- long time2 = System.currentTimeMillis();
- System.out.println("normal reflect invoke time:" + (time2 - time1));
- }
- /**
- * 缓存反射调用方法
- */
- private static void cacheReflectInvoke() {
- ReflectPerformanceDemo demo = new ReflectPerformanceDemo();
- try {
- Class<?> c = Class.forName("com.peter.demo.process.reflect.ReflectPerformanceDemo");
- Method method = c.getMethod("setmNum", Long.TYPE);
- long time1 = System.currentTimeMillis();
- for (long i = 0; i < TEST_TIMES; i++) {
- method.invoke(demo, i);
- demo.mSum += demo.getmNum();
- }
- long time2 = System.currentTimeMillis();
- System.out.println("cache invoke time:" + (time2 - time1));
- }
- catch (Exception e) {
- e.printStackTrace();
- }
- }
- /**
- * asm反射调用方法
- */
- private static void asmReflectInvoke() {
- ReflectPerformanceDemo demo = new ReflectPerformanceDemo();
- try {
- MethodAccess ma = MethodAccess.get(ReflectPerformanceDemo.class);
- int index = ma.getIndex("setmNum");
- long time1 = System.currentTimeMillis();
- for (long i = 0; i < TEST_TIMES; i++) {
- ma.invoke(demo, index, i);
- demo.mSum += demo.getmNum();
- }
- long time2 = System.currentTimeMillis();
- System.out.println("asm invoke time:" + (time2 - time1));
- }
- catch (Exception e) {
- e.printStackTrace();
- }
- }
- public long getmNum() {
- return mNum;
- }
- public void setmNum(long mNum) {
- this.mNum = mNum;
- }
- }
测试结果:
- normal invoke time:7
- normal reflect invoke time:1499
- cache invoke time:32
- asm invoke time:20
带缓存的反射调用方法速度明显慢于直接调用,采用asm第三方反射库,速度有少量提升。
反射慢的原因:Because reflection involves types that are dynamically resolved, certain Javavirtual machine optimizations can not be performed. Consequently, reflective operations have slower performance than their non-reflective counterparts, and should be avoided in sections of code which are called frequently in performance-sensitive applications.
(五)应用场景
(1)“基于构件的编程”,在这种编程方式中,将使用某种基于快速应用开发(RAD)的应用构建工具来构建项目。这是现在最常见的可视化编程方法,通过代表不同组件的图标拖动到图板上来创建程序,然后设置构件的属性值来配置它们。这种配置要求构件都是可实例化的,并且要暴露其部分信息,使得程序员可以读取和设置构件的值。
(2)能够提供在跨网络的远程平台上创建和运行对象的能力,实现java语言的网络可移动性。这被成为远程调用(RMI),它允许一个Java程序将对象分步在多台机器上,这种分步能力将帮助开发人员执行一些需要进行大量计算的任务,充分利用计算机资源,提高运行速度。
(六)范例
破解最可靠的单例模式,在这个例子中,最可靠的又可以lazy loading的是第五种单例模式创建,但是可以通过反射机制破除安全性。
- /**
- * 安全的单例模式
- *
- * @author peter_wang
- * @create-time 2014-6-10 下午4:45:20
- */
- public class SingletonSafe {
- private SingletonSafe() {
- System.out.println("create singleton");
- }
- private static class StaticSingleton {
- private static SingletonSafe instance = new SingletonSafe();
- }
- public static SingletonSafe getInstance() {
- return StaticSingleton.instance;
- }
- }
- /**
- * 测试反射
- *
- * @author peter_wang
- * @create-time 2014-6-10 下午5:08:58
- */
- public class ReflectDemo {
- /**
- * @param args
- */
- public static void main(String[] args) {
- try {
- Class classInstance = Class.forName("com.peter.demo.process.reflect.SingletonSafe");
- System.out.println(classInstance.getName());
- Constructor cons = classInstance.getDeclaredConstructor(null);
- cons.setAccessible(true);
- SingletonSafe singletonSafe1 = (SingletonSafe) cons.newInstance(null);
- System.out.println("singleton1:" + singletonSafe1.toString());
- SingletonSafe singletonSafe2 = (SingletonSafe) cons.newInstance(null);
- System.out.println("singleton2:" + singletonSafe2.toString());
- Method method1 = classInstance.getDeclaredMethod("getInstance", null);
- SingletonSafe singletonSafe3 = (SingletonSafe) method1.invoke(classInstance, null);
- System.out.println("singleton3:" + singletonSafe3.toString());
- Method method2 = classInstance.getDeclaredMethod("getInstance", null);
- SingletonSafe singletonSafe4 = (SingletonSafe) method2.invoke(classInstance, null);
- System.out.println("singleton4:" + singletonSafe4.toString());
- }
- catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
测试结果:
- com.peter.demo.process.reflect.SingletonSafe
- create singleton
- singleton1:com.peter.demo.process.reflect.SingletonSafe@2a9931f5
- create singleton
- singleton2:com.peter.demo.process.reflect.SingletonSafe@2f9ee1ac
- create singleton
- singleton3:com.peter.demo.process.reflect.SingletonSafe@5f186fab
- singleton4:com.peter.demo.process.reflect.SingletonSafe@5f186fab
由测试结果可知,
单例模式可以用反射创建多个对象。
(七)总结
目前的计算机系统的速度,应用开发已不在过于在意性能,而更为注重系统的可维护性和扩展性以及快速开发效率上。上述的测试结果是在大量操作基础上产生的。而在通常的一次业务请求中,反射使用的次数应该是非常少的,只在框架级基础上被使用,在一个高负载的系统中,业务处理的性能将是关键点,而不在于使用的这些反射所带来的性能影响上。而使用反射所带来的开发便利与可维护性可扩展性的提升所带来的价值,是远远高于其所损耗的性能的。
java-反射深度剖析的更多相关文章
- Java反射机制剖析(四)-深度剖析动态代理原理及总结
动态代理类原理(示例代码参见java反射机制剖析(三)) a) 理解上面的动态代理示例流程 a) 理解上面的动态代理示例流程 b) 代理接口实现类源代码剖析 咱们一起来剖析一下代理实现类($Pr ...
- Java反射机制剖析(三)-简单谈谈动态代理
通过Java反射机制剖析(一)和Java反射机制剖析(二)的学习,已经对反射有了一定的了解,这一篇通过动态代理的例子来进一步学习反射机制. 1. 代理模式 代理模式就是为其他对象提供一种代理来 ...
- Java反射机制剖析(二)-功能以及举例
从<java反射机制剖析(一)>的API我们看到了许多接口和类,我们能够通过这些接口做些什么呢? 从上篇API中我们能看到它能够完成下面的这些功能: 1) 获得类 A. 运 ...
- Java反射机制剖析(一)-定义和API
1. 什么是Java反射机制 Java的反射机制是在程序运行时,能够完全知道任何一个类,及其它的属性和方法,并且能够任意调用一个对象的属性和方法.这种运行时的动态获取就是Java的反射机制.其 ...
- 【54】Java反射机制剖析
java反射机制: 1.指的是可以于运行时加载,探知和使用编译期间完全未知的类. 2.程序在运行状态中, 可以动态加载一个只有名称的类, 对于任意一个已经加载的类,都能够知道这个类的所有属性和方法; ...
- java反射机制剖析(二)— Class Loader
上一篇博客简要的提了一下java反射机制中涉及到的一些相关知识,那么ClassLoader就是当中之中的一个.本篇博客就具体的对ClassLoader做一个相对深入的了解. 作为了解须要知道的是.事实 ...
- java初始化深度剖析
当用一个类来创建对象的时候,JVM会帮我们执行下面的6个步骤. 1.在磁盘上找到对应内的class文件: 2.加载class文件到内存,初始化所有静态域(成员变量和方法): 3.如果使用new cla ...
- Java反射机制深度剖析
版权声明:本文为博主原创文章,转载请注明出处,欢迎交流学习! Java反射机制是Java语言中一种很重要的机制,可能在工作中用到的机会不多,但是在很多框架中都有用到这种机制.我们知道Java是一门静态 ...
- 深度剖析java中JDK动态代理机制
https://www.jb51.net/article/110342.htm 本篇文章主要介绍了深度剖析java中JDK动态代理机制 ,动态代理避免了开发人员编写各个繁锁的静态代理类,只需简单地指定 ...
- Java 反射在实际开发中的应用
运行时类型识别(RTTI, Run-Time Type Information)是Java中非常有用的机制,在java中,有两种RTTI的方式,一种是传统的,即假设在编译时已经知道了所有的类型:还有一 ...
随机推荐
- Web Service的工作原理
Web Service基本概念 Web Service也叫XML Web Service WebService是一种可以接收从Internet或者Intranet上的其它系统中传递过来的请求,轻量级的 ...
- Django之Model进阶的更多操作
Django之Model进阶的更多操作 一.字段 AutoField(Field) - int自增列,必须填入参数 primary_key=True BigAutoField(AutoField) ...
- Oracle复合B*tree索引branch block内是否包含非先导列键值?
好久不碰数据库底层细节的东西,前几天,一个小家伙跑来找我,非要说复合b*tree index branch block中只包含先导列键值信息,并不包含非先导列键值信息,而且还dump了branch b ...
- android studio 何如修改报名
1. 重命名办法,网上很多见 2. 对于需要重新修改包名的级别的 a. 修改package 和 gradle 的包名,对应一致. b. 修改R 所在包名,使用crtl+n修改R文件的路径 c. 手动首 ...
- JS笔记(一)
第一章: 编写JS流程: 1. 布局:HTML和CSS 2. 样式:修改页面元素样式,div的display样式 3. 事件:确定用户做什么操作,onclick(鼠标点击事件).onmouseo ...
- 开源博客系统使用springmvc
https://github.com/Zephery/newblog http://www.wenzhihuai.com/index.html
- Hibernate(五):Hibernate配置文件及C3P0的用法
配置文件可配项: 参考文档:hibernate-release-5.2.9.Final/documentation/userguide/html_single/Hibernate_User_Guide ...
- [论文阅读] Joint Face Detection and Alignment using Multi-task Cascaded Convolutional Networks(MTCNN)
相关论文:Joint Face Detection and Alignment using Multi-task Cascaded Convolutional Networks 概论 用于人脸检测和对 ...
- spring boot 系列之四:spring boot 整合JPA
上一篇我们讲了spring boot 整合JdbcTemplate来进行数据的持久化, 这篇我们来说下怎么通过spring boot 整合JPA来实现数据的持久化. 一.代码实现 修改pom,引入依赖 ...
- 编程基础学习JS的入门教程
将JavaScript 插入网页的方法 使用<script>标签在网页中插入Javascript代码. 插入JavaScript 与在网页中插入CSS的方式相似.使用下面的代码可以在网页中 ...