JAVA反射基础(摘抄自"侯捷谈JAVA反射机制")

Java反射机制

关键词:

Introspection(内省、内观)

Reflection(反射)

##反射机制是java的高级技巧,世界上著名的框架struts,hibernate,spring的实现,无不用到了反射机制,反射机制可以让代码灵活,从而实现可配置化。


##Reflection
这个字的意思是“反射、映象、倒影”,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods1。这种“看透class”的能力(the ability of the program to examine itself)被称为introspection(内省、内观、反省)。Reflection和introspection是常被并提的两个术语。

##Class
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.
Class是Reflection故事起源。针对任何您想探勘的class,唯有先为它产生一个Class object,接下来才能经由后者唤起为数十多个的Reflection APIs。这些APIs将在稍后的探险活动中一一亮相。


##"Class” object的取得途径
Java允许我们从多种管道为一个class生成对应的Class object
1.getClass(),每个class 都有此函数

示例 String str = "abc";
Class c1 = str.getClass();

2.Class.getSuperclass()

示例 Button b = new Button();

Class c1 = b.getClass();

Class c2 = c1.getSuperclass();

3.运用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");

4.运用.class 语法
示例 Class c1 = String.class;

Class c2 = java.awt.Button.class;

Class c3 = Main.InnerClass.class;

Class c4 = int.class;

Class c5 = int[].class;

5.运用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 Reflection API 运用示例
Class c = Class.forName("");

c.getPackage();//得到Package
c.getDeclaredFields//得到类的所有字段
c.getDeclaredConstructors();//得到类的所有构造函数
c.getDeclaredMethods();();//得到类的所有方法
。。。其他不详细描述,查询java api即可

##
找出class参用(导入)的所有classes

没有直接可用的Reflection API可以为我们找出某个class参用的所有其它classes。要获得这项信息,必须做苦工,一步一脚印逐一记录。我们必须观察所有fields的类型、所有methods(包括constructors)的参数类型和回返类型,剔除重复,留下唯一。这正是为什么图5-2程序代码要为tName()指定一个hashtable(而非一个null)做为第二自变量的缘故:hashtable可为我们储存元素(本例为字符串),又保证不重复。



本文讨论至此,几乎可以还原一个class的原貌(唯有methods 和ctors的定义无法取得)。接下来讨论Reflection 的另三个动态性质:(1) 运行时生成instances,(2) 执

行期唤起methods,(3) 运行时改动fields。



运行时生成instances

欲生成对象实体,在Reflection 动态机制中有两种作法,一个针对“无自变量ctor”,

一个针对“带参数ctor”。图6是面对“无自变量ctor”的例子。如果欲调用的是“带参数ctor“就比较麻烦些,图7是个例子,其中不再调用Class的newInstance(),而是调用Constructor 的newInstance()。图7首先准备一个Class[]做为ctor的参数类型(本例指定为一个double和一个int),然后以此为自变量调用getConstructor(),获得一个专属ctor。接下来再准备一个Object[] 做为ctor实参值(本例指定3.14159和125),调用上述专属ctor的newInstance()。



#001 Class c = Class.forName("DynTest");

#002 Object obj = null;

#003 obj = c.newInstance(); //不带自变量

#004 System.out.println(obj);

图6:动态生成“Class object 所对应之class”的对象实体;无自变量。



#001 Class c = Class.forName("DynTest");

#002 Class[] pTypes = new Class[] { double.class, int.class };

#003 Constructor ctor = c.getConstructor(pTypes);

#004 //指定parameter list,便可获得特定之ctor

#005

#006 Object obj = null;

#007 Object[] arg = new Object[] {3.14159, 125}; //自变量

#008 obj = ctor.newInstance(arg);

#009 System.out.println(obj);

图7:动态生成“Class object 对应之class”的对象实体;自变量以Object[]表示。



运行时调用methods

这个动作和上述调用“带参数之ctor”相当类似。首先准备一个Class[]做为ctor的参数类型(本例指定其中一个是String,另一个是Hashtable),然后以此为自变量调用getMethod(),获得特定的Method object。接下来准备一个Object[]放置自变量,然后调用上述所得之特定Method object的invoke(),如图8。知道为什么索取Method object时不需指定回返类型吗?因为method overloading机制要求signature(署名式)必须唯一,而回返类型并非signature的一个成份。换句话说,只要指定了method名称和参数列,就一定指出了一个独一无二的method。



#001 public String func(String s, Hashtable ht)

#002 {

#003 …System.out.println("func invoked"); return s;

#004 }

#005 public static void main(String args[])

#006 {

#007 Class c = Class.forName("Test");

#008 Class ptypes[] = new Class[2];

#009 ptypes[0] = Class.forName("java.lang.String");

#010 ptypes[1] = Class.forName("java.util.Hashtable");

#011 Method m = c.getMethod("func",ptypes);

#012 Test obj = new Test();

#013 Object args[] = new Object[2];

#014 arg[0] = new String("Hello,world");

#015 arg[1] = null;

#016 Object r = m.invoke(obj, arg);

#017 Integer rval = (String)r;

#018 System.out.println(rval);

#019 }

图8:动态唤起method



运行时变更fields内容

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



#001 public class Test {

#002 public double d;

#003

#004 public static void main(String args[])

#005 {

#006 Class c = Class.forName("Test");

#007 Field f = c.getField("d"); //指定field 名称

#008 Test obj = new Test();

#009 System.out.println("d= " + (Double)f.get(obj));

#010 f.set(obj, 12.34);

#011 System.out.println("d= " + obj.d);

#012 }

#013 }









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