Reflection 是Java被视为动态(或准动态)语言的一个关键性质。这个机制允许程序在运行时通过Reflection APIs取得任何一个已知名称class的内部信息,包括其modifiers、superclass、interfaces,也包括fields和methods的所有信息,并可于运行时改变fields的值或执行methods。下面通过例子介绍Java的反射机制和Reflection APIs。让大家知道如何反射class的结构、如何对某个“运行时才获知名称的class”生成一个实例、为其fields设值、调用其methods。本文将谈到java.lang.Class,以及java.lang.reflect中的Method、Field、Constructor等等classes。
Class class
众所周知Java有个Object class,是所有Java classes的继承根源,其内声明了数个应该在所有Java class中被重写的methods:hashCode()、equals()、clone()、toString(),getClass()等。其中getClass()返回一个Class object。Class class十分特殊。它和一般classes一样继承自Object,其实体用以表达Java程序运行时的classes和interfaces,也用来表达array、primitive Java types(boolean, byte, char, short, int, long, float, double)以及关键词void。当一个class被装载,或当类装载器(class loader)的defineClass()被JVM调用时,JVM 便自动产生一个Class object。如果您想借由“修改Java标准库源码”来观察Class object的实际生成时机(例如在Class的constructor内添加一个println()),不能够!因为Class并没有public constructor(参看下在的源码)。
Class是Reflection的起点。针对任何您想射的class,唯有先为它产生一个Class object,接下来才能经这个对象和数十个Reflection APIs协同工作,完成反射任务。





















仔细看一下上面的源码。他的构造方法是private并且为空,这就意味着不允许任何人使用编程的方式产生Class object。其object 只能由JVM 产生。
Class object的取得方法:
Java允许我们从多种方法为一个class生成对应的Class object。整理如下:
Class object 产生方法 | 示例 |
运用getClass() | String str = "abc"; Class c1 = str.getClass();
|
运用Class.getSuperclass() | Button b = new Button(); Class c1 = b.getClass(); Class c2 = c1.getSuperclass(); |
运用static method Class.forName()(最常被使用) | Class c1 = Class.forName ("java.lang. String"); Class c2 = Class.forName ("java.awt.Button"); Class c3 = Class.forName ("java.util. LinkedList$Entry"); Class c4 = Class.forName ("I"); Class c5 = Class.forName ("[I"); |
运用.class 语法 | Class c1 = String.class; Class c2 = java.awt.Button.class; Class c3 = Main.InnerClass.class; Class c4 = int.class; Class c5 = int[].class;
|
运用 primitive wrapper classes的TYPE 语法 | Class c1 = Boolean.TYPE; Class c2 = Byte.TYPE; Class c3 = Character.TYPE; Class c4 = Short.TYPE; Class c5 = Integer.TYPE; Class c6 = Long.TYPE; Class c7 = Float.TYPE; Class c8 = Double.TYPE; Class c9 = Void.TYPE; |
Java classes 组成分析
首先以Employee为例,将Java class的定义进行分解,每一块对应相应的Reflection API








































上面的Java class成份,分别对应于下表的Reflection API,其中出现的Package、Method、Constructor、Field等等classes,都定义于java.lang.reflect。
Java class 内 部模块 | Java class 内部模块说明 | 相应之Reflection API,多半为Class methods。 | 返回值类型(return type) |
(1) package | class隶属哪个package | getPackage() | Package |
(2) import | class导入哪些classes | -- | -- |
(3)modifier | class(或methods,fields)的属性 | int getModifiers() Modifier.toString(int)Modifier.isInterface(int) | int String bool |
(4) class name or Interface name | class/interface名称 | getName() | String |
(5) base class | base class(只可能一个) | getSuperClass() | Class |
(6)Implemented interfaces | 实现有哪些interfaces | getInterfaces() | Class[] |
(7) fields | 字段(成员变量)不论 public 或private 或其它access level,皆可获得 | getDeclaredFields() | Field[] |
(8) type parameters | 参数化类型的名称 | getTypeParameters() | TypeVariable<Class>[] |
(9) inner classes | 内部classes | getDeclaredClasses() | Class[] |
(9') outer class | 如果我们观察的class 本身是inner classes,那么相对它就会有个outer class。 | getDeclaringClass() | Class |
(10) constructors | 构造函数不论 public 或private 或其它access level,皆可获 | getDeclaredConstructors() | Constructor[]
|
(11) methods | 操作函数不论 public 或private 或其它access level,皆可获得。 | getDeclaredMethods()
| Method[]
|
以上是每一块所对应的Reflection API(并非Reflection APIs 的全部)。通过以上API我们几乎可以还原一个类的源代码(构造方法和方法的定义不能得到).对于导入的类比较麻烦,因为没有直接提供相应的API。我们必须观察所有fields的类型、所有methods(包括constructors)的参数类型和回返类型,去掉重复的,留下唯一。有兴趣可以一起讨论.
Java Reflection API
Java Reflection 有三个动态性质:(1) 运行时生成instances,(2) 执行期间调用methods,(3) 运行时更改动fields。
运行时生成instances
要生成对象实例,在Reflection 动态机制中有两种作法,一个针对“无参数的构造方法”,一个针对“带参数的构造方法”。下面分别介绍如下:
无参数的构造方法

















带参数的构造方法
调用的是“带参数的构造方法”就比较麻烦些,其中不再调用Class的newInstance(),而是调用Constructor 的newInstance()。首先准备一个Class[]做为构造方法的参数类型(本例指定为一个String和一个List),然后用该变量调用getConstructor(),获得一个指定参数的构造方法.接下来再准备一个Object[] 做为构造方法实参值,调用上述指定构造方法的newInstance()。






















执行期间调用methods
这个动作和上述调用“带参数的构造方法”相当类似。首先准备一个Class[]做为方法的参数类型,然后以此为自变量调用getMethod(),获得特定的Method object。接下来准备一个Object[]放置参数值,然后调用上述所得之特定Method object的invoke()。获取Method object时不需指定方法的返回类型吗?因为method overloading机制要求signature(签名)必须唯一,而返回类型并非signature的一个成份。换句话说,只要指定了method名称和参数列表,就能确定一个唯一的方法。























运行时更改动Fields
与先前两个动作相比,“更改field内容”轻松多了,因为它不需要参数和自变量。首先调用Class的getField()并指定field名称。获得特定的Field object之后便可直接调用Field的get()和set().





















小结
本文只对java反射API作了基本的介绍.希望对大家有所帮助.在程序中还有一些细节不是很完善.比如:如何访问受保护的域,如何反射类中所导入的其它类.以后将对这些方面进行介绍,并给出java反射在对象持久化中的运用.
以下是java源代码和本文的word文档.
http://dl2.youkuaiyun.com/down4/20070722/22215048468.rar