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反射机制 有助深入理解Java新特性
侯捷谈java反射机制 收藏 这篇文章对反射讲得挺深入的,值得收藏
JAVA反射侯捷观点 JAVA反射侯捷观点
Reflection 是Java被视为动态(或准动态)语言的一个关键性质。本文借由实例,大面积示范Reflection APIs
Thinking in Java 高清晰PDF版 侯捷著。 Java学习的经典好书,不用多说。收藏。
轻松些个Undable 程序
侯捷翻译的3本JAVA书的例子代码
3本侯捷写的JAVA书(强烈推荐)--非常经典的书,java学者不可缺少的参考书 3本侯捷写的JAVA书(强烈推荐)--非常经典的书,java学者不可缺少的参考书 3本侯捷写的JAVA书(强烈推荐)--非常经典的书,java学者不可...
3本侯捷写的JAVA书(强烈推荐) 不要资源分,给那些么没有积分的人下载
《侯捷 - C++内存管理机制_60_侯捷》30.G2.9std_alloc观念大整理
侯捷-Java编程思想+第2版(繁体版).pdf
这本书很经典,就不多介绍了
Reflection 是Java 被視為動態(或準動態)語言的㆒個關鍵性質。這個機制允許程 式在執行期透過Reflection APIs 取得任何㆒個已知名稱的class 的內部資訊,包括 其modifiers(諸如public, static 等等)、superclass...
虽然繁体,但是有英文!
Practical Java (侯捷 刘永丹译-超星版
博文链接:https://xiaoyongxin.iteye.com/blog/229997
《侯捷 - C++内存管理机制_60_侯捷》25.G2.9std_alloc运行一瞥06-10
java大师畅谈侯捷--源码追踪经验谈 分为上下册pdf版
侯捷先生谈程序员与编程 简体中文版 侯捷先生
《侯捷 - C++内存管理机制_60_侯捷》27.G2.9std_alloc源码剖析(上)