简明扼要的反射入门教程

反射

反射作为RTTI语言(比如Java)的基础之一被很多人所熟知,但是有些同学对反射本身还是懵懵懂懂的,不是很清楚它到底有什么用。今天这节课我们就对反射本身来一个通体的认知。

定义

反射所在的包为:java.lang.reflect

它的英文版定义是:Reflection allows programmatic access to information about the fields, methods and constructors of loaded classes。the use of reflected fields, methods, and constructors to operate on their underlying counterparts, within security restrictions.

By default, a reflected object is not accessible.

Setting the accessible flag in a reflected object permits sophisticated applications with sufficient privilege, such as Java Object Serialization or other persistence mechanisms, to manipulate objects in a manner that would normally be prohibited.

Java反射主要是指程序可以访问或者修改它本身状态或行为的一种能力,是Java被视为动态(或准动态)语言的一个关键性质。这个机制允许程序在运行时通过Reflection APIs取得任何一个已知名称的class的内部信息,包括其modifiers(诸如public, static 等)、superclass(例如Object)、实现之interfaces(例如Cloneable),也包括fields和methods的所有信息,并可于运行时改变fields内容或唤起methods。

PS: 因为反射机制与Class类联系紧密,所以在学习反射之前需要先了解Class类是什么。

Android文档中的反射定义:https://developer.android.google.cn/reference/java/lang/reflect/package-summary.html

作用

动态的访问、修改类的成员,可以达到使用常规手段做不到的目的。

最常见的例子:一个类有一个私有的成员属性,无法通过正常的手段(比如Get方法)获取这个属性的值,那么就需要通过反射来获得它的值,

反射多用于框架和组件,通过反射可以写出复用性高的通用程序。

比如我们所熟知的Android中的Activity就是通过反射实例化生成的。

    public Activity newActivity(ClassLoader cl, String className, Intent intent) throws InstantiationException, IllegalAccessException, ClassNotFoundException {return (Activity)cl.loadClass(className).newInstance();}

最后这行代码通过字符串形式的类路径加载指定的Activity类到内存中,然后通过反射的newInstance()实例化Activity对象,最后通过向下转型返回给调用者。

上面这段代码位于android.app.Instrumentation内。同理,我们所熟知的Application,Service,ContentProvider,BroadcatReceiver也是通过这种方式生成的。

Java多态的伟大之处就从这里开始!

你可能会有疑惑,为什么不直接new呢?

如果是new方法,那么new只能实例化指定的类,也就是说,如果使用new,Android系统框架只能实例化某个Activity了。而如果通过反射,那么只要是Activity的子类,都可以通过此方法实例化,这也就是多态的精髓。

优点

反射涉及到了动态与静态的概念:

  • 静态编译:在编译时确定类型,绑定对象,即通过。
  • 动态编译:运行时确定类型,绑定对象。动态编译最大限度发挥了java的灵活性,体现了多态的应用,用以降低类之间的藕合性。

反射机制的优点是可以实现动态创建对象以及修改对象的结构,体现出很大的灵活性。

缺点

它的缺点是对性能有影响。使用反射基本上是一种解释操作。由于用于字段和方法接入时反射要远慢于直接代码,反射在性能上会有所影响,但性能问题的程度取决于程序中是如何使用反射的。如果它作为程序运行中相对很少涉及的部分,缓慢的性能将不会是一个问题。即使测试中最坏情况下的计时图显示的反射操作只耗用几微秒。仅反射在性能关键的应用的核心逻辑中使用时性能问题才变得至关重要。所以,合理的使用反射将大大提高我们程序的通用性和复用性。

技术解析铺垫

运行时类型识别(Run-time Type Identification, RTTI)主要有两种方式,一种是我们在编译时和运行时已经知道了所有的类型,另外一种是功能强大的”反射”机制。

要理解RTTI在Java中的工作原理,首先必须知道类型信息在运行时是如何表示的,这项工作是由”Class对象”完成的,它包含了与类有关的信息。类是程序的重要组成部分,每个类都有一个Class对象,每当编写并编译了一个新类就会产生一个Class对象,它被保存在一个同名的.class文件中。在运行时,当我们想生成这个类的对象时,运行这个程序的Java虚拟机(JVM)会确认这个类的Class对象是否已经加载,如果尚未加载,JVM就会根据类名查找.class文件,并将其载入,一旦这个类的Class对象被载入内存,它就被用来创建这个类的所有对象。一般的RTTI形式包括三种:

1.传统的类型转换。如”(Apple)Fruit”,由RTTI确保类型转换的正确性,如果执行了一个错误的类型转换,就会抛出一个ClassCastException异常。

2.通过Class对象来获取对象的类型。如

    Class c = Class.forName("Apple");Object o = c.newInstance();

3.通过关键字instanceof或Class.isInstance()方法来确定对象是否属于某个特定类型的实例,准确的说,应该是instanceof / Class.isInstance()可以用来确定对象是否属于某个特定类及其所有基类的实例,这和equals() / ==不一样,它们用来比较两个对象是否属于同一个类的实例,没有考虑继承关系。

基本用法

以下分别展示了反射的基本用法:

类的获取方式

针对我们所知的不同情况分别有3种方法获取Class对象

  • 当已知类名的时候,通过”类名.class”获得

  • 当已知对象的时候,通过”对象.getClass”获得

  • 当已知包括包名在内的完整类名(假设为String格式)的时候,可通过”Class.forName(classPath)”或者”ClassLoader.loadClass(classPath)”获得

比如我们有一个类,类的结构如下:

package com.sahadev;/*** Created by Sahadev on 2017/4/27.*/public class ClassABean {public boolean mFlag;private IMethod mIMethod;public ClassABean() {}public ClassABean(boolean mFlag, IMethod iMethod) {super();this.mFlag = mFlag;this.mIMethod = iMethod;}private void printBValue(){System.out.println("The mFlag = " + mFlag);}
}

那么类ClassABean的字节码的获取方式有以下3种:

  • ClassABean.class;
  • new ClassABean().getClass();
  • Class.forName(“com.sahadev.ClassABean”);或者ClassLoader.loadClass(“com.sahadev.ClassABean”);

获取到Class字节码对象之后,我们就可以对其进行操作了。

通过无参构造方法实例化对象

通过无参构造的方式有两种,一种是我们上面看到的,使用newInstance()方法,而另一种是获得类的无参构造方法,然后通过无参构造方法创建对象。其中newInstance()方法默认调用的是无参构造方法,如果类没有无参构造方法,则会有异常抛出。

这两种方法的使用方式分别如下:

    //通过newInstance()方法构造ClassABean instanceA = ClassABean.class.newInstance();//通过无参构造方法构造Constructor<ClassABean> constructor = ClassABean.class.getConstructor();//获取无参构造方法ClassABean instanceB = constructor.newInstance();//实例化

通过有参构造方法实例化对象

通过有参构造方法实例化对象的方法如下:

    Constructor<ClassABean> constructor = ClassABean.class.getConstructor(Boolean.class, ClassBBean.class);//获取指定参数的构造方法ClassABean instanceB = constructor.newInstance(true, new ClassBBean());//通过对象参数实例化对象

上面的代码等价于:

    ClassABean instanceB  = new ClassABean(true, new ClassBBean());

通过以上有参构造方法构造的对象,它们的成员属性现在都已经被赋了值。其中属性mFlag的值为true,属性mIMethod的实际实现者为ClassBBean。

PS: 在我们的示例中提到的ClassBBean类与ClassCBean类都同样实现了IMethod接口。

方法调用

从以上的示例中我们知道了如何通过反射来实例化一个对象,接下来我们通过反射来调用一下类的私有方法。

在ClassABean类中提供了一个私有方法printBValue(),我们看看如何通过反射来调用这个方法:

    Method method = ClassABean.class.getDeclaredMethod("printBValue");ClassABean instanceB = new ClassABean(true,new ClassBBean());method.setAccessible(true);method.invoke(instanceB);

控制台会正确输出我们预想中的值:

The mFlag = true

这样调用和我们通过普通方法调用的效果是一致的,只是反射可以调用类的私有方法。

在这里细心的同学就会发现,Class类本身提供了两个获取方法的方法,一个是getDeclaredMethod,另一个是getMethod。那这两者有什么区别呢?getDeclaredMethod用于获取所有的方法,包括私有方法。而getMethod则用于获取public方法,其它权限方法无法获得。

属性获取与赋值

属性的获取与方法类同:

    Field flagField = ClassABean.class.getDeclaredField("mFlag");flagField.setAccessible(true);ClassABean classABeanInstance = new ClassABean(true, new ClassBBean());boolean flag = (boolean) flagField.get(classABeanInstance);

这样就可以获得对象classABeanInstance的mFlag的值,同样的,我们还可以获得属性mIMethod的值:

    Field iMethodField = ClassABean.class.getDeclaredField("mIMethod");iMethodField.setAccessible(true);ClassABean classABeanInstance = new ClassABean(true, new ClassBBean());IMethod iMethod = (IMethod) iMethodField.get(classABeanInstance);

其中IMethod的具体实例为ClassBBean对象。

接下来我们演示一下如何替换属性的值,这种方式在很多地方都很常见,它的用途很广:

    Field iMethodField = ClassABean.class.getDeclaredField("mIMethod");iMethodField.setAccessible(true);ClassABean classABeanInstance = new ClassABean(true, new ClassBBean());ClassCBean classCBean = new ClassCBean();iMethodField.set(classABeanInstance, classCBean);IMethod iMethod = (IMethod) iMethodField.get(classABeanInstance);

通过这样的方式,我们再获取mIMethod的值将会是classCBean对象。我们在这里使用了set的方法,set方法用于给指定对象的属性赋值。

用例1(修改TextView的autoLink的点击实现)

相关文章介绍:如何修改TextView链接点击实现(包含链接生成与点击原理分析)

用例2(热修复实现)

相关文章介绍:一步步手动实现热修复

扩展了解

通过反射我们可以获得一个类的注解,它的父类以及实现的接口等。了解反射可以有助于我们实现抽象能力更强的框架。

扩展阅读:https://developer.android.google.cn/reference/java/lang/Class.html

参考地址

http://c.biancheng.net/cpp/html/1781.html
http://www.voidcn.com/blog/zbuger/article/p-5771880.html
http://www.fanyilun.me/2015/10/29/Java反射原理/
http://rednaxelafx.iteye.com/blog/548536
http://blog.csdn.net/u013551462/article/details/51261817

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/478722.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

人在斯坦福,刚上CS224n

文 | Jazon大家好&#xff0c;我是Jazon&#xff0c;现在是Stanford计算机硕士项目的一只学生&#xff0c;非常荣幸加入小夕的大家庭&#xff01;请各路大神多多指教呀。2021年1月12日&#xff0c;又一季Stanford CS224n——自然语言处理开课了&#xff0c;我和很多MSCS同学一起…

美团外卖骑手背后的AI技术

背景 随着数字化时代的到来&#xff0c;外卖市场近年来发展非常迅猛。对外卖物流系统而言&#xff0c;配送效率和用户体验至关重要。而实际配送过程是由配送员&#xff08;骑手&#xff09;最终完成的&#xff0c;因此&#xff0c;想要真正提升配送效率&#xff0c;不但要在智能…

软件设计师:下午试题类型以及问题总结+软件设计师考试下午题统计分析(06到2019年)

‘’’ 首次更新下午试题 ‘’’ 下午考试时间为150分钟&#xff08;14:00–16:30&#xff09; 试题一到四为必答题&#xff0c;试题五和六为选答一个&#xff0c;每题15分&#xff0c;总共75分&#xff0c;每题大概3小问 第一题为结构化分析与设计&#xff0c;考查数据流…

LeetCode 494. 目标和(DFS+DP)

文章目录1. 题目2. 解题2.1 递归2.2 DP1. 题目 给定一个非负整数数组&#xff0c;a1, a2, …, an, 和一个目标数&#xff0c;S。现在你有两个符号 和 -。对于数组中的任意一个整数&#xff0c;你都可以从 或 -中选择一个符号添加在前面。 返回可以使最终数组和为目标数 S 的…

使用Kotlin开发Android应用初体验

使用Kotlin开发Android应用初体验 昨晚&#xff0c;最近一届的谷歌IO大会正式将Kotlin确定为了官方开发语言&#xff0c;作为一名Android开发鸟&#xff0c;怎么能不及时尝尝鲜呢? Kotlin的简要介绍 在开发之前&#xff0c;很多同学一定有很多疑问&#xff0c;Kotlin到底有…

论文浅尝 - ICML2020 | 基于子图推理的归纳式关系预测

论文笔记整理&#xff1a;陈名杨&#xff0c;浙江大学在读博士生&#xff0c;主要研究方向为知识图谱表示学习。论文来源&#xff1a;ICML 2020Introduction当前在知识图谱上&#xff08;KnowledgeGraph&#xff0c;KG&#xff09;进行关系预测的很多方法都依靠在对知识图谱中的…

CVPR 二十年,影响力最大的 10 篇论文!

文 | 二玖极市平台此前&#xff0c;极市盘点了图像分割在过去二十年中影响力最大的10篇论文&#xff0c;得到了许多开发者的支持。今天&#xff0c;我们将对计算机视觉领域三大顶会之一CVPR在近二十年来中产生的优秀论文进行一个全面的盘点与总结。CVPR是计算机视觉领域三大顶会…

DataMan-美团旅行数据质量监管平台实践

背景 数据&#xff0c;已经成为互联网企业非常依赖的新型重要资产。数据质量的好坏直接关系到信息的精准度&#xff0c;也影响到企业的生存和竞争力。Michael Hammer&#xff08;《Reengineering the Corporation》一书的作者&#xff09;曾说过&#xff0c;看起来不起眼的数据…

jupyter notebook切换到其他配置好的conda虚拟环境

1 手把手教你如何把jupyter notebook切换到其他配置好的conda虚拟环境 https://blog.csdn.net/weixin_41813895/article/details/84750990 2 Jupyter notebook切换Python环境 https://www.jianshu.com/p/8188c32a3a34

LeetCode 133. 克隆图(图的BFS/DFS)

1. 题目 给定无向连通图中一个节点的引用&#xff0c;返回该图的深拷贝&#xff08;克隆&#xff09;。图中的每个节点都包含它的值 val&#xff08;Int&#xff09; 和其邻居的列表&#xff08;list[Node]&#xff09;。 class Node { public:int val;vector<Node*> n…

七天搞定java接口自动化测试实战,一文搞定...

前言 无论是自动化测试还是自动化部署&#xff0c;撸码肯定少不了&#xff0c;所以下面的基于java语言的接口自动化测试&#xff0c;要想在业务上实现接口自动化&#xff0c;前提是要有一定的java基础。 如果没有java基础&#xff0c;也没关系。这里小编也为大家提供了一套jav…

Android自动化测试探索

前言 通常来说&#xff0c;我们开发完成产品之后&#xff0c;都是由测试组或者是我们自己点一点&#xff0c;基本上没有问题了就开始上线。但是&#xff0c;随着时间的堆叠&#xff0c;一款产品的功能也越来越多。这时&#xff0c;我们为了保证产品的质量&#xff0c;就需要在…

我整理了100道大厂算法岗面试必考题!

最近&#xff0c;很多小伙伴给我留言去面试被面试官吊打了&#xff0c;尤其是一些去面大厂的朋友&#xff0c;甚至一面都没有过...来&#xff0c;别灰心&#xff0c;我以过往经验告诉你大厂面试的通关秘诀&#xff01;对&#xff0c;就是算法&#xff01;大厂面试必考算法&…

参会邀请 - ISWC2020 | 第十九届国际语义网会议

第十九届国际语义网会议&#xff08;ISWC2020&#xff09;将于11月1日至6日远程召开。国际语义网会议是全球最重要的且最有影响力的国际学术会议&#xff0c;主要聚焦语义网&#xff0c;知识图谱&#xff0c;本体&#xff0c;链接数据等面向互联网的人工智能技术。国际语义网会…

美团配送资金安全治理之对账体系建设

前言 随着美团配送业务的飞速发展&#xff0c;单量已经达到千万级别&#xff0c;同时每天产生的资金额已经超过几千万&#xff0c;清结算系统在保证线上服务稳定可靠的前提下&#xff0c;如何系统化的保障资金安全是非常核心且重要的课题&#xff0c;配送清结算系统经过近3年的…

Githug第42关rebase_onto通关秘籍

Githug是一个用来了解、熟悉Git的一个非常好的游戏。 目前网站上收录的都是之前只有55关的解题方法&#xff0c;没有新增的rebase_onto这一关的内容。现在Githug一共有56关。现将新增的42关的解答内容更新如下&#xff1a; 第42关的题目如下: Name: rebase_onto Level: 41 D…

gcc安装不行的解决办法,需更新apt-get

上面应该更新apt-get 更新之后&#xff0c;重新安装gcc成功

LeetCode 138. 复制带随机指针的链表(哈希 / 深拷贝)

1. 题目 给定一个链表&#xff0c;每个节点包含一个额外增加的随机指针&#xff0c;该指针可以指向链表中的任何节点或空节点。 要求返回这个链表的深拷贝。 《剑指Offer》同题&#xff1a;面试题35. 复杂链表的复制 2. 解题 类似题目&#xff1a;LeetCode 1484. 克隆含随…

论文浅尝 - COLING2020 | 桥接文本和知识的多原型嵌入在少样本关系三元组抽取中的研究...

本文转载自公众号&#xff1a;浙大KG。 论文题目&#xff1a;Bridging Text and Knowledge with Multi-Prototype Embedding for Few-Shot Relational Triple Extraction本文作者&#xff1a;余海阳发表会议&#xff1a;COLING 2020论文链接&#xff1a;https://person.zju.…

惊呆!不用一张图片,却训出个图像识别SOTA?

文 &#xff5c; 橙橙子如果老板派给你一个任务&#xff0c;不使用一张图片&#xff0c;让你训练一个视觉预训练模型&#xff0c;你会不会觉得老板疯了。最近有一篇论文&#xff0c;不仅没用一张真实图片和标注&#xff0c;还训练出个媲美SOTA的效果&#xff0c;甚至超过了MoCo…