从Introspector谈Java内省机制

http://cwind.iteye.com/blog/2007496

内省
内省是Java语言的一种重要特性。使用内省我们可以在运行时得到一个类的内部信息。这些信息包括方法、属性、构造函数及其他。内省的一个应用是开发使用插件的应用程序。应用程序可以在运行时获取并使用插件类的构造函数、方法和属性。内省也可以应用于创建Java Beans和Javadocs中。
Introspector类
Introspector类为访问目标Jave Bean支持的属性、事件和方法提供了标准方法。该方法可用于工具类(如BeanUtils)中。
对于属性、事件和方法中的每一类信息,Introspector会分别分析目标bean以及其父类,寻找显式或隐式信息并用其构建一个能够全面描述目标bean的BeanInfo对象。
通过调用Introspector.getBeanInfo()方法来获得指定类的bean信息。Java Bean规范允许通过实现BeanInfo接口,定义一个对象来描述bean。为了将BeanInfo与bean关联起来,须遵守如下命名模式:bean信息类的名字必须是将"BeanInfo"添加到bean名字的后面构成。例如:
Java代码   收藏代码
  1. package com.cwind.introspector;  
  2.   
  3. public class Ultraman extends Superhero {  
  4.         public String avanta ;  
  5.   
  6.         public Ultraman(String avanta) {  
  7.                super ();  
  8.                this .avanta = avanta;  
  9.        }  
  10.   
  11.         public String getAvanta() {  
  12.                return avanta ;  
  13.        }  
  14.   
  15.         public void setAvanta(String avanta) {  
  16.                this .avanta = avanta;  
  17.        }  
  18. }  
 相关信息类:
Java代码   收藏代码
  1. package com.cwind.introspector;  
  2.   
  3. import java.beans.IntrospectionException;  
  4. import java.beans.PropertyDescriptor;  
  5. import java.beans.SimpleBeanInfo;  
  6.   
  7. public class UltramanBeanInfo extends SimpleBeanInfo {  
  8.         public PropertyDescriptor[] getPropertyDescriptors() {  
  9.                try {  
  10.                       return new PropertyDescriptor[]{  
  11.                             new PropertyDescriptor("avanta" , Ultraman. class),  
  12.                             new PropertyDescriptor("name" , Ultraman. class)  
  13.                      };  
  14.               } catch (IntrospectionException e) {  
  15.                      e.printStackTrace();  
  16.                       return null ;  
  17.               }  
  18.        }  
  19. }  
信息类会先从Bean类所在的包内查找,如上例中搜索路径为com.cwind.introspector.UltramanBeanInfo。搜索路径也可以通过Introspector.setBeanInfoSearchPath()进行设置。使用BeanInfo类是为了获取对bean属性的控制权。只需提供属性名和所属的bean类,就可以为每个属性构建一个PropertyDescriptor。
演示类Superhero及其另一子类Titan定义:
Java代码   收藏代码
  1. package com.cwind.introspector;  
  2.   
  3. public class Superhero {  
  4.      private String name ;  
  5.      private String superPower ;  
  6.      private int age ;  
  7.          
  8.      public Superhero(){  
  9.           this.name = "defaultName" ;  
  10.           this.superPower  = "defaultSuperPower" ;  
  11.           this.age = 0;  
  12.      }  
  13.          
  14.      public Superhero(String name, String superPower, int age) {  
  15.           super();  
  16.           this.name = name;  
  17.           this.superPower = superPower;  
  18.           this.age = age;  
  19.      }  
  20.   
  21.      public String getName() {  
  22.           return name ;  
  23.      }  
  24.      public void setName(String name) {  
  25.           this.name = name;  
  26.      }  
  27.      public String getSuperPower() {  
  28.           return superPower ;  
  29.      }  
  30.      public void setSuperPower(String superPower) {  
  31.           this.superPower = superPower;  
  32.      }  
  33.      public int getAge() {  
  34.           return age ;  
  35.      }  
  36.      public void setAge(int age) {  
  37.           this.age = age;  
  38.      }  
  39. }  
  40.   
  41. package com.cwind.introspector;  
  42.   
  43. public class Titan extends Superhero {  
  44.      private double height ;  
  45.      private double weight ;  
  46.          
  47.      public Titan(double height, double weight) {  
  48.           super();  
  49.           this.height = height;  
  50.           this.weight = weight;  
  51.      }  
  52.          
  53.      public double getHeight() {  
  54.           return height ;  
  55.      }  
  56.      public void setHeight(double height) {  
  57.           this.height = height;  
  58.      }  
  59.      public double getWeight() {  
  60.           return weight ;  
  61.      }  
  62.      public void setWeight(double weight) {  
  63.           this.weight = weight;  
  64.      }    
  65. }  
 
可以看到,Ultraman类有一个显式的BeanInfo类,其中的属性描述符仅包括"avanta"和继承自父类的"name"。Titan没有显式的BeanInfo类。下面用一个测试类来打印Introspector获取的BeanInfo信息,分别打印两个Ultraman和Titan实例的属性名称及其对应的值,比较其异同。
Java代码   收藏代码
  1. package com.cwind.introspector;  
  2.   
  3. import java.beans.IntrospectionException;  
  4. import java.beans.Introspector;  
  5. import java.beans.PropertyDescriptor;  
  6. import java.lang.reflect.InvocationTargetException;  
  7.   
  8. public class IntrospectorTest {  
  9.      public static void main(String[] args) throws IntrospectionException, IllegalArgumentException, IllegalAccessException, InvocationTargetException{  
  10.           PropertyDescriptor[] ultramanProps = Introspector.getBeanInfo(Ultraman.class).getPropertyDescriptors();  
  11.           Ultraman sailor = new Ultraman("sailor" );  
  12.           for(PropertyDescriptor prop : ultramanProps){  
  13.                System. out.println("Property name: " + prop.getName()+ ", value: "+ prop.getReadMethod().invoke(sailor, null));  
  14.           }  
  15.           System. out.println();  
  16.           PropertyDescriptor[] titanProps = Introspector.getBeanInfo(Titan.class).getPropertyDescriptors();  
  17.           Titan titan = new Titan(999,888);  
  18.           for(PropertyDescriptor prop : titanProps){  
  19.                System. out.println("Property name: " + prop.getName()+ ", value: "+ prop.getReadMethod().invoke(titan, null));  
  20.           }  
  21.      }  
  22. }  
 
输出结果如下:
Java代码   收藏代码
  1. Property name: avanta, value: sailor  
  2. Property name: name, value: defaultName  
  3.   
  4. Property name: age, value: 0  
  5. Property name: class, value: class com.cwind.introspector.Titan  
  6. Property name: height, value: 999.0  
  7. Property name: name, value: defaultName  
  8. Property name: superPower, value: defaultSuperPower  
  9. Property name: weight, value: 888.0  
 
可以看到,对于前者,只打印出其显式BeanInfo类中返回的属性描述符所对应的属性;对于后者,使用低层次的反射来获取所有属性,并按照属性名称字母序将属性描述符数组返回。
为了更好的性能,Introspector缓存BeanInfo;因此,若在使用多个类加载器的应用程序中使用Introspector须小心谨慎。可以调用Introspector.flushCaches或Introspector.flushFromCaches方法从缓存中清空内省的类。
Reference:
6. Java2核心技术 卷II:高级特性,第8章:JavaBean构件;【美】Cay S. Horstmann, Gary Cornell 著;机械工业出版社

    • 0
      点赞
    • 0
      收藏
      觉得还不错? 一键收藏
    • 0
      评论

    “相关推荐”对你有帮助么?

    • 非常没帮助
    • 没帮助
    • 一般
    • 有帮助
    • 非常有帮助
    提交
    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

    当前余额3.43前往充值 >
    需支付:10.00
    成就一亿技术人!
    领取后你会自动成为博主和红包主的粉丝 规则
    hope_wisdom
    发出的红包
    实付
    使用余额支付
    点击重新获取
    扫码支付
    钱包余额 0

    抵扣说明:

    1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
    2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

    余额充值