传智播客Spring2.5视频教程_编码剖析Spring依赖注入的原理 4

来源:互联网 发布:mac储存空间正在计算 编辑:程序博客网 时间:2024/05/29 03:54

出处http://kdisk-sina-com.javaeye.com/blog/230995

 

 

2008-08-21

反射 (Reflection) 和内省 (Introspector)

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

反射

相对而言,反射比内省更容易理解一点。用一句比较白的话来概括,反射就是让你可以通过名称来得到对象 ( 类,属性,方法 ) 的技术。例如我们可以通过类名来生成一个类的实例;知道了方法名,就可以调用这个方法;知道了属性名就可以访问这个属性的值。

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

Java代码 复制代码
  1. 引用   
  2. //通过类名来构造一个类的实例    
  3. Class cls_str = Class.forName( "java.lang.String" );    
  4. // 上面这句很眼熟,因为使用过 JDBC 访问数据库的人都用过 J    
  5. Object str = cls_str.newInstance();    
  6. // 相当于 String str = new String();    
  7. //通过方法名来调用一个方法    
  8. String methodName = "length" ;    
  9. Method m = cls_str.getMethod(methodName, null );    
  10. System.out.println( "length is " + m.invoke(str, null ));    
  11. // 相当于 System.out.println(str.length());  


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

关于方法的反射建议大家看我的另外一篇文章《 利用 Turbine 的事件映射来扩展 Struts 的功能 》,地址是: http://www.javayou.com/article/CSDN/extend_struts.html 。这篇文章详细介绍了如果通过反射来扩展 Struts 框架的功能。

内省

内省是 Java 语言对 Bean 类属性、事件的一种缺省处理方法。例如类 A 中有属性 name, 那我们可以通过 getName,setName 来得到其值或者设置新的值。通过 getName/setName 来访问 name 属性,这就是默认的规则。 Java 中提供了一套 API 用来访问某个属性的 getter/setter 方法,通过这些 API 可以使你不需要了解这个规则(但你最好还是要搞清楚),这些 API 存放于包 java.beans 中。


一般的做法是通过类 Introspector 来获取某个对象的 BeanInfo 信息,然后通过 BeanInfo 来获取属性的描述器( PropertyDescriptor ),通过这个属性描述器就可以获取某个属性对应的 getter/setter 方法,然后我们就可以通过反射机制来调用这些方法。下面我们来看一个例子,这个例子把某个对象的所有属性名称和值都打印出来:
Java代码 复制代码
  1. 引用   
  2. /*   
  3. * Created on 2004-6-29   
  4. */    
  5.   
  6. package demo;    
  7.   
  8.   
  9. import java.beans.BeanInfo;    
  10. import java.beans.Introspector;    
  11. import java.beans.PropertyDescriptor;    
  12.   
  13.   
  14. /**   
  15. * 内省演示例子   
  16. * @author liudong   
  17. */    
  18.   
  19. public class IntrospectorDemo {    
  20. String name;    
  21. public static void main(String[] args) throws Exception{    
  22. IntrospectorDemo demo = new IntrospectorDemo();    
  23. demo.setName( "Winter Lau" );    
  24.   
  25. // 如果不想把父类的属性也列出来的话,    
  26. // 那 getBeanInfo 的第二个参数填写父类的信息    
  27. BeanInfo bi = Introspector.getBeanInfo(demo.getClass(), Object. class );    
  28. PropertyDescriptor[] props = bi.getPropertyDescriptors();    
  29. for ( int i=0;i<props.length;i++){    
  30. System.out.println(props[i].getName()+ "=" +    
  31. props[i].getReadMethod().invoke(demo, null ));    
  32. }    
  33.   
  34. }    
  35.   
  36. public String getName() {    
  37. return name;    
  38. }    
  39.   
  40. public void setName(String name) {    
  41. this .name = name;    
  42. }    
  43. }   

Web 开发框架 Struts 中的 FormBean 就是通过内省机制来将表单中的数据映射到类的属性上,因此要求 FormBean 的每个属性要有 getter/setter 方法。但也并不总是这样,什么意思呢?就是说对一个 Bean 类来讲,我可以没有属性,但是只要有 getter/setter 方法中的其中一个,那么 Java 的内省机制就会认为存在一个属性,比如类中有方法 setMobile ,那么就认为存在一个 mobile 的属性,这样可以方便我们把 Bean 类通过一个接口来定义而不用去关心具体实现,不用去关心 Bean 中数据的存储。比如我们可以把所有的 getter/setter 方法放到接口里定义,但是真正数据的存取则是在具体类中去实现,这样可提高系统的扩展性。

总结
将 Java 的反射以及内省应用到程序设计中去可以大大的提供程序的智能化和可扩展性。有很多项目都是采取这两种技术来实现其核心功能,例如我们前面提到的 Struts ,还有用于处理 XML 文件的 Digester 项目,其实应该说几乎所有的项目都或多或少的采用这两种技术。在实际应用过程中二者要相互结合方能发挥真正的智能化以及高度可扩展性。
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
·································································································································································
2008-08-21

类Introspector的使用

关键字: introspector
Java代码 复制代码
  1. import javax.swing.*;   
  2. import java.awt.*;   
  3. import java.awt.event.*;   
  4. import java.beans.*;   
  5. import java.io.*;   
  6. import java.lang.reflect.Method;   
  7. public class myBeanIntrospector   
  8. {   
  9.  public myBeanIntrospector()   
  10.  {   
  11.   try  
  12.   {   
  13.    //实例化一个Bean   
  14.    Student beanObj = new Student();   
  15.    //依据Bean产生一个相关的BeanInfo类   
  16.    BeanInfo bInfoObject =    
  17.    Introspector.getBeanInfo(beanObj.getClass(),beanObj.getClass().getSuperclass());   
  18.    //定义一个用于显示的字符串   
  19.    String output = "";   
  20.   
  21.    //开始自省   
  22.     
  23.    /*  
  24.    * BeanInfo.getMethodDescriptors()  
  25.    * 用于获取该Bean中的所有允许公开的成员方法,以MethodDescriptor数组的形式返回  
  26.    *  
  27.    * MethodDescriptor类  
  28.    * 用于记载一个成员方法的所有信息  
  29.    * MethodDescriptor.getName()  
  30.    * 获得该方法的方法名字  
  31.    * MethodDescriptor.getMethod()  
  32.    * 获得该方法的方法对象(Method类)  
  33.    *  
  34.    * Method类  
  35.    * 记载一个具体的的方法的所有信息  
  36.    * Method.getParameterTypes()  
  37.    * 获得该方法所用到的所有参数,以Class数组的形式返回  
  38.    *  
  39.    * Class..getName()  
  40.    * 获得该类型的名字  
  41.    */  
  42.    output = "内省成员方法:/n";   
  43.    MethodDescriptor[] mDescArray = bInfoObject.getMethodDescriptors();   
  44.    for (int i=0;i<mDescArray.length ;i++ )   
  45.    {   
  46.     //获得一个成员方法描述器所代表的方法的名字   
  47.     String methodName = mDescArray[i].getName();   
  48.        
  49.     String methodParams = new String();   
  50.     //获得该方法对象   
  51.     Method methodObj = mDescArray[i].getMethod();   
  52.     //通过方法对象获得该方法的所有参数,以Class数组的形式返回   
  53.     Class[] parameters = methodObj.getParameterTypes();   
  54.     if (parameters.length>0)   
  55.     {   
  56.      //获得参数的类型的名字   
  57.      methodParams = parameters[0].getName();   
  58.      for (int j=1;j<parameters.length ;j++ )   
  59.      {   
  60.       methodParams = methodParams + "," + parameters[j].getName();   
  61.      }   
  62.     }   
  63.     output += methodName + "(" + methodParams + ")/n";   
  64.    }   
  65.    System.out.println(output);   
  66.     
  67.    /*  
  68.    * BeanInfo.getPropertyDescriptors()  
  69.    * 用于获取该Bean中的所有允许公开的成员属性,以PropertyDescriptor数组的形式返回  
  70.    *  
  71.    * PropertyDescriptor类  
  72.    * 用于描述一个成员属性  
  73.    *  
  74.    * PropertyDescriptor.getName()  
  75.    * 获得该属性的名字  
  76.    *  
  77.    * PropertyDescriptor.getPropertyType()  
  78.    * 获得该属性的数据类型,以Class的形式给出  
  79.    *  
  80.    */  
  81.    output = "内省成员属性:/n";   
  82.    PropertyDescriptor[] mPropertyArray = bInfoObject.getPropertyDescriptors();   
  83.    for (int i=0;i<mPropertyArray.length ;i++ )   
  84.    {   
  85.     String propertyName = mPropertyArray[i].getName();   
  86.     Class propertyType = mPropertyArray[i].getPropertyType();   
  87.     output += propertyName + " ( " + propertyType.getName() + " )/n";   
  88.    }   
  89.    System.out.println(output);   
  90.     
  91.   
  92.    /*  
  93.    * BeanInfo.getEventSetDescriptors()  
  94.    * 用于获取该Bean中的所有允许公开的成员事件,以EventSetDescriptor数组的形式返回  
  95.    *  
  96.    * EventSetDescriptor类  
  97.    * 用于描述一个成员事件  
  98.    *  
  99.    * EventSetDescriptor.getName()  
  100.    * 获得该事件的名字  
  101.    *  
  102.    * EventSetDescriptor.getListenerType()  
  103.    * 获得该事件所依赖的事件监听器,以Class的形式给出  
  104.    *  
  105.    */  
  106.    output = "内省绑定事件:/n";   
  107.    EventSetDescriptor[] mEventArray = bInfoObject.getEventSetDescriptors();   
  108.    for (int i=0;i<mEventArray.length ;i++ )   
  109.    {   
  110.     String EventName = mEventArray[i].getName();   
  111.     Class listenerType = mEventArray[i].getListenerType();   
  112.     output += EventName + "(" + listenerType.getName() + ")/n";   
  113.    }   
  114.    System.out.println(output);   
  115.    System.out.println("write by esonghui :)");   
  116.     
  117.   }   
  118.   catch (Exception e)   
  119.   {   
  120.    System.out.println("异常:" + e);   
  121.   }   
  122.  }   
  123.  public static void main(String[] args)    
  124.  {   
  125.   new myBeanIntrospector();   
  126.  }   
  127. }   
  128.    
原创粉丝点击