反射,是指一种能在运行时动态加载、分析类的能力。反射被广泛地用于那些需要在运行时检测或修改程序行为的程序中。这是一个相对高级的特性,使用反射技术应当具备相当的Java语言基础。我们可以通过反射机制让应用程序做一些几乎不可能做到的事情。
一. Class类
在java.lang包中有一个特殊的类,即Class类。JVM会为所有被加载的类创建一个对应的Class类的对象,这个对象保存了类的运行时信息。我们可以通过Class对象得到对应的类的一些特征,如类的名字,类有哪些属性,有哪些方法,类的超类是谁,甚至可以直接调用类中的方法。Class类是Java反射技术的基础。
三种获取Class实例的方法:
1. 通过Object.getClass()方法获取。
Object类是所有类的超类,在这个类中有一个getClass()方法,它可以返回这个类的Class对象。我们自定义一个简单的Point类来进行测试:
class Point
{
}
Point pt = new Point();
Class c1 = pt.getClass(); //通过getClass()方法得到Class对象
2. 通过 类.class 方式获取
如果我们只知道一个类类型,没有此类的一个实例,那么就可以这样:
Class c2 = Point.class;
也就是说,每个类都有一个静态的class成员,可以直接用 类.class的方式得到。
3.通过Class.forName()方式获取
Class的静态方法forName()允许我们通过类的全名来得到Class对象。它需要一个字符串作为参数:
Class c3 = Class.forName("Point");
这时候需要捕获一个 ClassNotFoundException.
二、通过Class对象调用构造函数、成员方法
1. 调用无参数的构造函数创建对象
我们上面定义的Point类并没有定义构造方法,因此编译器会为我们提供一个无参数的默认构造方法。如果想要通过这个无参数的构造方法,则只需要调用Class的newInstance()方法即可得到Point类的一个实例:
Point pt2 = (Point)c1.newInstance(); //newInstance返回Object,因此需要强制转换
2.调用有参数的构造函数创建对象
现在我们为Point类添加一个有参数的构造方法:
class Point
{
public Point(int i)
{
System.out.println(i);
}
}
如果我们想要调用这个带参数的构造方法,则必须先用
Class对象的getConstructors() 方法来得到一个表示(标识为public)构造方法的对象的数组。在java.lang.reflect包中有一个Constructor类,这个类就代表了一个构造方法。因此getConstructors()
返回的是Constructor[] 数组。
Constructor[] cons = c1.getConstructors();
因为我们定义的Point类显然只有一个构造函数,所以我们直接使用cons[0]。
在Constructor类中,也有一个newInstance()方法,不过这个方法是带参数的,需要传递一个Object类型的数组。为什么呢?因为我们要调用的构造方法是带参数的,如果不告诉编译器这些参数应该怎么填,那就无法成功地调用该构造方法了。因此,这个Object数组顺理成章地应该就是要传递的参数了。
那么如何才能知道构造方法需要什么类型的参数,到底有几个参数呢?我们可以调用Constructor中的getParameterTypes()来获取所有参数的类型,该方法返回一个Class[]数组,数组中的每一个元素就代表了参数的类型。如本例中,Point的构造方法有一个int 类型的参数,那么返回的Class[]数组就只有一个元素,且这个元素会是一个Integer类的Class对象。当得知参数类型是Integer后,我们就可以为构造方法传递参数了。示例:
Constructor[] cons = c1.getConstructors();
Class[] parmsType = cons[0].getParameterTypes(); //得到参数的类型
Object[] parms = new Object[parmsType.length]; //这个数组用来为newInstance()传参
//遍历parmsType数组,并为Object数组赋值
for(int i = 0 ; i < parms.length ; ++i)
{
if(parmsType[i].isPrimitive()) //判断是否是基本数据类型
{
parms[i] = new Integer(100);
}
}
此时就可以创建Point对象了:
Point pt = (Point)cons[0].newInstance(parms);
此时,我们看到控制台打印出100,说明Point类构造成功。
3.调用Class所对应类的成员方法
先通过Class的getDeclaredMethods()方法来得到所有被声明的方法,即返回一个Method[]类型的数组。然后可以调用Method对象的invoke()方法实现方法的调用。invoke()依然分有参和无参两种情况。此时的调用方式与上面调用newInstance()的过程类似,不再赘述。
三、反射的缺点:(从官方指南上找的,个人翻译水平差,大家凑合看。。。。意会就行。。)
Reflection is powerful, but should not be used indiscriminately. If it is possible to perform an operation without using reflection, then it is preferable to avoid using it. The following concerns should be kept in mind when accessing
code via reflection.
尽管反射非常强大,但也不能滥用。如果一个功能可以不用反射完成,那么最好就不用。在我们使用反射技术时,下面几条内容应该牢记于心:
性能第一Performance Overhead
Because reflection involves types that are dynamically resolved, certain Java virtual 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.
反射包括了一些动态类型,所以JVM无法对这些代码进行优化。因此,反射操作的效率要比那些非反射操作低得多。我们应该避免在经常被 执行的代码或对性能要求很高的程序中使用反射。
安全限制Security Restrictions
Reflection requires a runtime permission which may not be present when running under a security manager. This is in an important consideration for code which has to run in a restricted security context, such as in an Applet.
使用反射技术要求程序必须在一个没有安全限制的环境中运行。如果一个程序必须在有安全限制的环境中运行,如Applet,那么这就是个问题了。。
内部暴露Exposure of Internals
Since reflection allows code to perform operations that would be illegal in non-reflective code, such as accessingprivate
fields and methods, the use of reflection can result in unexpected side-effects, which may render code dysfunctional and
may destroy portability. Reflective code breaks abstractions and therefore may change behavior with upgrades of the platform.
由于反射允许代码执行一些在正常情况下不被允许的操作(比如访问私有的属性和方法),所以使用反射可能会导致意料之外的副作用--代码有功能上的错误,降低可移植性。反射代码破坏了抽象性,因此当平台发生改变的时候,代码的行为就有可能也随着变化。
分享到:
相关推荐
在不知道类名的情况下如何动态的使用其构造方法来创建对象和不知道其方法名的时候如何动态地使用其方法。
java反射全解(反射原理+反射API详解+反射与数组+反射与泛型+反射源码与性能开销+反射优缺点+反射与内省)
php反射api.pdf
Java IOC(控制反转)及反射api应用代码参考实例
mirror,Java反射API上的简单DSL层.zip
PHP面向对象程序设计之类与反射API详解共5页.pdf.zip
镜像js 简单JavaScript反射API。 我将此模块供我个人使用,但请不要犹豫,在这里!安装$ npm install mirror-js用法var baseObj = { } ;var mirror = require ( 'mirror-js' ) ;var clone = mirror ( baseObj ) . ...
OkReflect,OKFISH是一个试图帮助您轻松使用Java反射API的库。.zip
jOOR,java joor中的joor-fluent反射是一个非常简单的fluent api,它以更直观的方式提供对java类结构的...jdk的反射api很难使用,而且冗长。其他语言有更简单的结构来在运行时访问类型元信息。让我们改进Java反射。.zip
反射API可以获取程序在运行时刻的内部结构,反射API提供的动态代理是非常强大的功能,可以原生的实现AOP中的方法拦截功能,反射API就好像在看一个Java类在水中的倒影,知道Java类的内部结构,就可以和它们进行交互,...
如何使用反射API 示例代码 Person.php Person类,包含一个成员变量和三个成员方法 获取$student对象的方法和属性列表 ReflectionClass类报告了一个类的有关信息 输出结果为:name say __set __get 也可以用class...
本文实例为大家分享了 PHP反射API–利用反射技术实现的插件系统架构,供大家参考,具体内容如下 <?php /** * @name PHP反射API--利用反射技术实现的插件系统架构 */ /** * 先调用findPlugins方法获取到获取到...
反射API的实现,用于解析PHP源文件。 这允许反射而无需加载类。 由于PHP无法卸载类,因此当您需要检查类但无需加载类(例如提取元数据)时,这对于减少内存占用非常有用。 以下是在drupal 8测试类上将“反射”与...
更好的体现是一种反射API,旨在改善和提供更多的功能比PHP的内置 。 为什么会更好? 您可以考虑尚未加载的类,而无需加载它们 能够直接从一串PHP代码反映出类 Better Reflection分析DocBlocks(使用 ) 直接反映...
避免运行时反射的反射API。价值成本 反映获取/设置界面{},并进行类型检查 反映获取/设置不安全的指针,无需类型检查 reflect2.TypeByName工作方式类似于Java中的Class.forName 使用此软件包可以节省运行时调度...
反射 SystemVerilog 的反射 API
TinyRefl 正在进行的最小C ++静态反射API和代码生成工具。特征反映类和枚举: 类和枚举名称用户声明的构造函数公众成员职能公共成员变量枚举值所有反射实体上的用户定义属性C ++ 14静态反射API :将枚举值转换为字符...
最近在开发过程中需要获取某个类方法的参数数量、名称及参数顺序,好根据参数的名称...采用PHP的反射API,获得函数参数名称和参数默认值的方法如下: 复制代码 代码如下: <?php class testClass{ public fu