要想理解反射的原理,首先要了解什么是类型信息 。JAVA让我们在运行时识别对象和类的信息,主要有两种方式:一种是传统的RTTI(Run-Time Type Identification),它假定我们在编译时已经知道了所有的类型信息;另一种是反射机制,它允许我们在运行时发现和使用类的信息 。
使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码)
一、反射的概述JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制 。
要想解剖一个类,必须先要获取到该类的字节码文件对象 。而解剖使用的就是Class类中的方法 。所以先要获取到每一个字节码文件对应的Class类型的对象. 。
反射就是把Java类中的各种成分映射成一个个的Java对象 。
例如:
一个类有:成员变量、方法、构造方法、包等等信息,利用反射技术可以对一个类进行解剖,把各个组成部分映射成一个个对象 。
(其实:一个类中这些成员方法、构造方法,在加入类中都有一个类来描述)
如图是类的正常加载过程:反射的原理在于class对象 。
熟悉一下加载的时候:Class对象的由来是将class文件读入内存,并为之创建一个Class对象 。
文章插图
类的正常加载过程
二、反射的理解反射之中包含了一个「反」字,所以想要解释反射就必须先从「正」开始解释 。
一般情况下,我们使用某个类时必定知道它是什么类,是用来做什么的 。于是我们直接对这个类进行实例化,之后使用这个类对象进行操作 。
如:
Phone phone = new Phone(); //直接初始化,「正射」
phone.setPrice(4);
上面这样子进行类对象的初始化,我们可以理解为「正」 。
而反射则是一开始并不知道我要初始化的类对象是什么,自然也无法使用 new 关键字来创建对象了 。
这时候,我们使用 JDK 提供的反射 API 进行反射调用:
Class clz = Class.forName("com.xxp.reflect.Phone");Method method = clz.getMethod("setPrice", int.class);Constructor constructor = clz.getConstructor();Object object = constructor.newInstance();method.invoke(object, 4);上面两段代码的执行结果,其实是完全一样的 。但是其思路完全不一样,第一段代码在未运行时就已经确定了要运行的类(Phone),而第二段代码则是在运行时通过字符串值才得知要运行的类(com.xxp.reflect.Phone) 。
所以说什么是反射?反射就是在运行时才知道要操作的类是什么,并且可以在运行时获取类的完整构造,并调用对应的方法 。
一般情况下我们使用反射获取一个对象的步骤:
//获取类的 Class 对象实例
Class clz = Class.forName("com.xxp.api.Phone");
//根据 Class 对象实例获取 Constructor 对象
【Java反射机制是开发第三方架构的基础】Constructor phoneConstructor = clz.getConstructor();
//使用 Constructor 对象的 newInstance 方法获取反射类对象
Object phoneObj = phoneConstructor.newInstance();
而如果要调用某一个方法,则需要经过下面的步骤:
//获取方法的 Method 对象
Method setPriceMethod = clz.getMethod("setPrice", int.class);
//利用 invoke 方法调用方法
setPriceMethod.invoke(phoneObj, 6000);
到这里,我们已经能够掌握反射的基本使用 。但如果要进一步掌握反射,还需要对反射的常用 API 有更深入的理解 。
三、反射的常用API在 JDK 中,反射相关的 API 可以分为下面几个方面:获取反射的 Class 对象、通过反射创建类对象、通过反射获取类属性方法及构造器 。
反射常用API:
获取反射中的Class对象
在反射中,要获取一个类或调用一个类的方法,我们首先需要获取到该类的 Class 对象 。
在 Java API 中,获取 Class 类对象有三种方法:
- 使用 Class.forName 静态方法 。当知道某类的全路径名时,可以使用此方法获取 Class 类对象 。用的最多,但可能抛出 ClassNotFoundException 异常 。
- Class c1 = Class.forName(“java.lang.String”);
- 直接通过 类名.class 的方式得到,该方法最为安全可靠,程序性能更高 。这说明任何一个类都有一个隐含的静态成员变量 class 。这种方法只适合在编译前就知道操作的 Class 。
推荐阅读
- 是时候拯救我的 HTML 技术了
- Java中使用KCP协议
- Java 远程通讯技术及原理分析
- Java 读取本地 JSON 文件
- Java中如何实现线程的超时中断
- 1分钟带你看懂Java内部类
- HTML5 的JavaScript 客户端PDF解决方案——jsPDF
- JavaScript核心概念归纳整理
- Redis主从复制机制详解
- Javascript事件轮询