反射API
反射,是指一种能在运行时动态加载、分析类的能力。反射被广泛地用于那些需要在运行时检测或修改程序行为的程序中。这是一个相对高级的特性,使用反射技术应当具备相当的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 accessing
private 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.
由于反射允许代码执行一些在正常情况下不被允许的操作(比如访问私有的属性和方法),所以使用反射可能会导致意料之外的副作用--代码有功能上的错误,降低可移植性。反射代码破坏了抽象性,因此当平台发生改变的时候,代码的行为就有可能也随着变化。
反射API的更多相关文章
- PHP 高级编程(2/5) - 反射API
PHP 5 具有完整的反射 API,添加了对类.接口.函数.方法和扩展进行反向工程的能力. 此外,反射 API 提供了方法来取出函数.类和方法中的文档注释.通过使用反射API可以分析其他的类.接口.方 ...
- 了解一下OOP的反射API
PHP5的类和对象函数并没有告诉我们类内部的所有一切,而只是报告了它们的公共成员.要充分了解一个类,需要知道其私有成员和保护成员,还要知道其方法所期望的参数 .对此,使用反射API. 1 查看自定义类 ...
- PHP反射API
近期忙着写项目,没有学习什么特别新的东西,所以好长时间没有更新博客.我们的项目用的是lumen,是基于laravel的一个轻量级框架,我看到里面用到了一些反射API机制来帮助动态加载需要的类.判断方法 ...
- 反射——反射API,使用反射创建数组
反射API Java.lang.Reflect库 ① Class类与Java.lang.Reflect类库一起对反射的概念进行支持. ② java.lang包下: a) Cla ...
- Java学习笔记--反射API
反射API 1.反射API的介绍 通过反射API可以获取Java程序在运行时刻的内部结构.比如Java类中包含的构造方法.域和方法等元素,并可以与这些元素进行交换. 按照 一般地面向对象的设计 ...
- 详解PHP反射API
PHP中的反射API就像Java中的java.lang.reflect包一样.它由一系列可以分析属性.方法和类的内置类组成.它在某些方面和对象函数相似,比如get_class_vars(),但是更加灵 ...
- Java反射API研究(1)——注解Annotation
注解在表面上的意思,只是标记一下这一部分,最好的注解就是代码自身.而在java上,由于注解的特殊性,可以通过反射API获取,这种特性使得注解被广泛应用于各大框架,用于配置内容,代替xml文件配置. 要 ...
- JDK1.7新特性(4):java语言动态性之反射API
直接通过一个代码示例来熟悉java中通过反射来对构造函数/域以及方法处理的相关API: package com.rampage.jdk7.chapter2; import java.lang.refl ...
- PHP面向对象深入研究之【了解类】与【反射API】
了解类 class_exists验证类是否存在 <?php // TaskRunner.php $classname = "Task"; $path = "task ...
- Atitit.跨语言反射api 兼容性提升与增强 java c#。Net php js
Atitit.跨语言反射api 兼容性提升与增强 java c#.Net php js 1. 什么是反射1 1.1. 反射提供的主要功能:1 1.2. 实现反射的过程:1 ...
随机推荐
- C++ 自定义结构体和类 内存对齐
为什么要提出内存对齐? 比如这么一种处理器,它每次读写内存的时候都从某个8倍数的地址开始,一次读出或写入8个字节的数据,假如软件能保证double类型的数据都从8倍数地址开始,那么读或写一个doubl ...
- JS - 删除确认
<a href="javascript:if(confirm('确实要删除吗?'))location='<{:U('Admin/Update/deleteuserinfo', a ...
- 【JQuery】eval()出现missing after property id 错误。
是因为数据没有转换成json格式输出就直接eval了. 正确步骤:后台: JsonBinder.buildNormalBinder().toJson(list); 前台: eval('(${posit ...
- 第一篇:NSOperation的概念
一.说明 NSOperation的作口:配合使用NSOperation和NSOperationQueue也能实现多线程 NSOperation和NSOperationQueue实现多线程的具体步骤: ...
- 应用之间进行跳转,ComponentName的方式
从应用A跳转到应用B, 关键代码如下: 有以下几个注意点: 1.ComponentName cn = new ComponentName("com.terry", "co ...
- Core dotnet 命令大全
Core dotnet 命令大全 dotnet 命令大全,让你理解dotnet 命令. 本文将以一个实例串起 dotnet 所有命令,让你玩转dotnet 命令. 本篇文章编写环境为windows 1 ...
- ethtool命令
用途 显示或修改以太网卡的配置信息. 语法 ethtool [ -a | -c | -g | -i | -d | -k | -r | -S |] ethX ethtool [-A] ethX [aut ...
- C#动态增加边框
if (this.Width >= 600) { timer1.Enabled = false; } else { this.Width += 30; }
- java --对象流与对象的序列化
对象流 ObjectInputStream ObjectOutputStream类分别是InputStream和OutputStream的子类,对象输出流使用writeObject(Object ob ...
- Qt学习之路(60): 创建shared library
前段时间说了Qt一些类库的使用,今天来换一下口味,来看一下程序设计的问题.今天来说的是关于共享库 shared library. 如果你打开一些 Windows 应用程序的目录,你会发现有很多程序的 ...