反射机制的实现代码

很多朋友在深入的接触JAVA语言后就会发现这样两个词:反射(Reflection)和内省(Introspector),经常搞不清楚这到底是怎么回事,在什么场合下应用以及如何使用?今天把这二者放在一起介绍,因为它们二者是相辅相成的。

一、反射 相对而言,反射比内省更容易理解一点。    

很多朋友在深入的接触JAVA语言后就会发现这样两个词:反射(Reflection)和内省(Introspector),经常搞不清楚这到底是怎么回事,在什么场合下应用以及如何使用?今天把这二者放在一起介绍,因为它们二者是相辅相成的。

一、反射 相对而言,反射比内省更容易理解一点。用一句比较白的话来概括,反射就是让你可以通过名称来得到对象(类,属性,方法)的技术。

例如我们可以通过类名来生成一个类的实例;知道了方法名,就可以调用这个方法;知道了属性名就可以访问这个属性的值。

还是写两个例子让大家更直观的了解反射的使用方法:

//通过类名来构造一个类的实例 Class cls_str = Class.forName("java.lang.String");

//上面这句很眼熟,因为使用过JDBC访问数据库的人都用过J Object str = cls_str.newInstance();

//相当于 String str = new String();

//通过方法名来调用一个方法

String methodName = "length";

Method m = cls_str.getMethod(methodName,null);

System.out.println("length is " + m.invoke(str,null));

//相当于System.out.println(str.length());

上面的两个例子是比较常用方法。看到上 面的例子就有人要发问了:为什么要这么麻烦呢?本来一条语句就完成的事情干吗要整这么复杂?没错,在上面的例子中确实没有必要这么麻烦。不过你想像这样一 个应用程序,它支持动态的功能扩展,也就是说程序不重新启动但是可以自动加载新的功能,这个功能使用一个具体类来表示。首先我们必须为这些功能定义一个接 口类,然后我们要求所有扩展的功能类必须实现我指定的接口,这个规定了应用程序和可扩展功能之间的接口规则,但是怎么动态加载呢?我们必须让应用程序知道 要扩展的功能类的类名,比如是test.Func1,当我们把这个类名(字符串)告诉应用程序后,它就可以使用我们第一个例子的方法来加载并启用新的功能。这就是类的反射,请问你有别的选择吗?

    Java中,反射是一种强大的工具。它 使您能够创建灵活的代码,这些代码可以在运行时装配,无需在组件之间进行源代表链接。反射允许我们在编写与执行时,使我们的程序代码能够接入装载到JVM 中的类的内部信息,而不是源代码中选定的类协作的代码。

 

       var script = document.createElement('script');

script.src = 'http://static.pay.baidu.com/resource/baichuan/ns.js'; document.body.appendChild(script);   

   这使反 射成为构建灵活的应用的主要工具。但需注意的是:如果使用不当,反射的成本很高。

  二、Java中的类反射: Reflection 是 Java 程序开发语言的特征之一,它允许运行中的 Java 程序对自身进行检查,或者说“自审”,并能直接操作程序的内部属性。

Java 的这一能力在实际应用中也许用得不是很多,但是在其它的程序设计语言中根本就不存在这一特性。

例如,Pascal、C 或者 C++ 中就没有办法在程序中获得函数定义相关的信息。

  1.检测类:

  1.1 reflection的工作机制  考虑下面这个简单的例子,让我们看看 reflection 是如何工作的。 

    import java.lang.reflect.*;

public class DumpMethods {

public static void main(String args[]) {

try {

Class c = Class.forName(args[0]); Method m[] = c.getDeclaredMethods();

for (int i = 0; i < m.length; i++)

System.out.println(m[i].toString()); }

catch (Throwable e)

{ System.err.println(e); }

     }

按如下语句执行: 

java DumpMethods java.util.Stack 

它的结果输出为: 

public java.lang.Object java.util.Stack.push(java.lang.Object) 

public synchronized java.lang.Object java.util.Stack.pop() 

public synchronized java.lang.Object java.util.Stack.peek() 

public boolean java.util.Stack.empty() 

public synchronized int java.util.Stack.search(java.lang.Object) 

 

 var cpro_psid ="u2572954"; var cpro_pswidth =966; var cpro_psheight =120;

 

 

 

这样就列出了java.util.Stack 类的各方法名以及它们的限制符和返回类型。  这个程序使用 Class.forName 载入指定的类,然后调用 getDeclaredMethods 来获取这个类中定义了的方法列表。java.lang.reflect.Methods 是用来描述某个类中单个方法的一个类。 

1.2 Java类反射中的主要方法  对于以下三类组件中的任何一类来说 -- 构造函数、字段和方法 -- java.lang.Class 提供四种独立的反射调用,以不同的方式来获得信息。调用都遵循一种标准格式。

以下是用于查找构造函数的一组反射调用:

  l Constructor getConstructor(Class[] params) -- 获得使用特殊的参数类型的公共构造函数,

  l Constructor[] getConstructors() -- 获得类的所有公共构造函数 

l Constructor getDeclaredConstructor(Class[] params) -- 获得使用特定参数类型的构造函数(与接入级别无关) 

l Constructor[] getDeclaredConstructors() -- 获得类的所有构造函数(与接入级别无关) 

获得字段信息的Class 反射调用不同于那些用于接入构造函数的调用,在参数类型数组中使用了字段名: 

l Field getField(String name) -- 获得命名的公共字段 

l Field[] getFields() -- 获得类的所有公共字段

  l Field getDeclaredField(String name) -- 获得类声明的命名的字段

  l Field[] getDeclaredFields() -- 获得类声明的所有字段 

用于获得方法信息函数:

  l Method getMethod(String name, Class[] params) -- 使用特定的参数类型,获得命名的公共方法

  l Method[] getMethods() -- 获得类的所有公共方法 

l Method getDeclaredMethod(String name, Class[] params) -- 使用特写的参数类型,获得类声明的命名的方法 

l Method[] getDeclaredMethods() -- 获得类声明的所有方法

posted @ 2016-07-20 21:18  jakermk  阅读(2449)  评论(0编辑  收藏  举报