候捷谈Java反射机制

摘要
Reflection Java 被视为动态(或准动态)语言的一个关键性质。这个机制允许程序在运行时透过 Reflection APIs 取得任何一个已知名称的 class 的内部信息,包括其 modifiers (诸如 public,static 等等)、 superclass (例如 Object )、实现之 interfaces (例如 Cloneable ),也包括 fields methods 的所有信息,并可于运行时改变 fields 内容或唤起 methods 。本文借由实例,大面积示范 Reflection APIs
关于本文:
读者基础:具备 Java 语言基础。
本文适用工具: JDK1.5
关键词:
Introspection (内省、内观)
Reflection (反射)
有时候我们说某个语言具有很强的动态性,有时候我们会区分动态和静态的不同技术与作法。我们朗朗上口动态绑定( dynamic binding )、动态链接( dynamic linking )、动态加载( dynamic loading )等。然而 动态 一词其实没有绝对而普遍适用的严格定义,有时候甚至像对象导向当初被导入编程领域一样,一人一把号,各吹各的调。
一般而言,开发者社群说到动态语言,大致认同的一个定义是: 程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言 。从这个观点看, Perl Python Ruby 是动态语言, C++ Java C# 不是动态语言。
尽管在这样的定义与分类下 Java 不是动态语言,它却有着一个非常突出的动态相关机制: Reflection 。这个字的意思是 反射、映象、倒影 ,用在 Java 身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的 classes 。换句话说, Java 程序可以加载一个运行时才得知名称的 class ,获悉其完整构造(但不包括 methods 定义),并生成其对象实体、或对其 fields 设值、或唤起其 methods 1 。这种 看透 class 的能力( the ability of the program to examine itself )被称为 introspection 内省、内观、反省 )。 Reflection introspection 是常被并提的两个术语。
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 ,也用来表达 enum 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 (见 1 )。本文最后我会拨一小块篇幅顺带谈谈 Java 标准库源码的改动办法。
Class Reflection 故事起源。针对任何您想探勘的 class ,唯有先为它产生一个 Class object ,接下来才能经由后者唤起为数十多个的 Reflection APIs 。这些 APIs 将在稍后的探险活动中一一亮相。
#001 public final
#002 class Class <T> implements java.io.Serializable,
#003 java.lang.reflect.GenericDeclaration,
#004 java.lang.reflect.Type,
#005 java.lang.reflect.AnnotatedElement {
#006 private Class() {}
#007 public String toString () {
#008 return ( isInterface() ? "interface " :
#009 (isPrimitive() ? "" : "class "))
#010 + getName();
#011 }
...
1 Class class 片段。注意它的 private empty ctor ,意指不允许任何人经由编程方式产生 Class object 。是的,其 object 只能由 JVM 产生。
Class object 的取得途径
Java 允许我们从多种管道为一个 class 生成对应的 Class object 2 是一份整理。

Class object 诞生管道
示例
运用 getClass()
注:每个 class 都有此函数
String str = "abc";
Class c1 = str.getClass();
运用
Class.getSuperclass() 2
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;
2 Java 允许多种管道生成 Class object
Java classes 组成分析
首先容我以 3 java.util.LinkedList 为例,将 Java class 的定义大卸八块,每一块分别对应 4 所示的 Reflection API 5 则是“获得 class 各区块信息”的程序示例及执行结果,它们都取自本文示例程序的对应片段。
package java.util; //(1)
import java.lang.*; //(2)
public class LinkedList < E > //(3)(4)(5)
extends AbstractSequentialList <E> //(6)
implements List <E>, Queue <E>,
Cloneable, java.io.Serializable //(7)
{
private static class Entry <E> { }//(8)
public LinkedList () { } //(9)
public LinkedList (Collection<? extends E> c) { }
public E getFirst () { } //(10)
public E getLast () { }
private transient Entry<E> header = ;//(11)
private transient int size = 0;
}
3 :将一个 Java class 大卸八块,每块相应于一个或一组 Reflection APIs (图 4 )。
Java classes 各成份所对应的 Reflection APIs
3 的各个 Java class 成份,分别对应于 4 Reflection API ,其中出现的 Package Method Constructor 、Field 等等 classes ,都定义于 java.lang.reflect

Java class 内部模块(参见 3
Java class 内部模块说明
相应之 Reflection API ,多半为 Class methods
返回值类型 (return type)
(1) package
class 隶属哪个 package
getPackage()
Package
(2) import
class 导入哪些 classes
无直接对应之 API
解决办法见 5-2
(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) type parameters
参数化类型的名称
getTypeParameters()
TypeVariable <Class>[]
(6) base class
base class (只可能一个)
getSuperClass()
Class
(7) implemented interfaces
实现有哪些 interfaces
getInterfaces()
Class[]
(8) inner classes
内部 classes
getDeclaredClasses()
Class[]
(8') outer class
如果我们观察的 class 本身是 inner classes ,那么相对它就会有个 outer class
getDeclaringClass()
Class
(9) constructors
构造函数 getDeclaredConstructors()
不论 public private 或其它 access level ,皆可获得。另有功能近似之取得函数。
Constructor[]
(10) methods
操作函数 getDeclaredMethods()
不论 public private 或其它 access level ,皆可获得。另有功能近似之取得函数。
Method[]
(11) fields
字段(成员变量)
getDeclaredFields() 不论 public private 或其它 access level ,皆可获得。另有功能近似之取得函数。
Field[]
4 Java class 大卸八块后(如图 3 ),每一块所对应的 Reflection API 。本表并非
Reflection APIs 的全部。
Java Reflection API 运用示例
5 示范 4 提过的每一个 Reflection API ,及其执行结果。程序中出现的 tName() 是个辅助函数,可将其第一自变量所代表的 Java class 完整路径字符串 剥除路径部分,留下 class 名称,储存到第二自变量所代表的一个 hashtable 去并返回(如果第二自变量为 null ,就不储存而只是返回)。
#001 Class c = null;
#002 c = Class.forName (args[0]);
#003
#004 Package p;
#005 p = c. getPackage ();
#006
#007 if (p != null)
#008 System.out.println("package "+p. getName ()+";");
执行结果(例):
package java.util;
5-1 :找出 class 隶属的 package 。其中的 c 将继续沿用于以下各程序片段。
#001 ff = c. getDeclaredFields ();
#002 for (int i = 0; i < ff.length; i++)
#003 x = tName(ff[i].getType().getName(), classRef);
#004
#005 cn = c. getDeclaredConstructors ();
#006 for (int i = 0; i < cn.length; i++) {
#007 Class cx[] = cn[i].getParameterTypes();
#008 for (int j = 0; j < cx.length; j++)
#009 x = tName(cx[j].getName(), classRef);
#010 }
#011
#012 mm = c. getDeclaredMethods ();
#013 for (int i = 0; i < mm.length; i++) {
#014 x = tName(mm[i].getReturnType().getName(), classRef);
#015 Class cx[] = mm[i].getParameterTypes();
#016 for (int j = 0; j < cx.length; j++)
#017 x = tName(cx[j].getName(), classRef);
#018 }
#019 classRef.remove(c.getName()); // 不必记录自己(不需 import 自己)
执行结果(例):
import java.
分享到:
评论

你可能感兴趣的:(java,jvm,C++,c,C#)